Thu Apr 3 08:20:40 2014

Asterisk developer's documentation


app_meetme.c File Reference

Meet me conference bridge and Shared Line Appearances. More...

#include "asterisk.h"
#include <dahdi/user.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/astobj2.h"
#include "asterisk/devicestate.h"
#include "asterisk/dial.h"
#include "asterisk/causes.h"
#include "asterisk/paths.h"
#include "asterisk/data.h"
#include "asterisk/test.h"
#include "enter.h"
#include "leave.h"
Include dependency graph for app_meetme.c:

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  dial_trunk_args
struct  run_station_args
struct  sla_event
struct  sla_failed_station
 A station that failed to be dialed. More...
struct  sla_ringing_station
 A station that is ringing. More...
struct  sla_ringing_trunk
 A trunk that is ringing. More...
struct  sla_station
struct  sla_station_ref
 A reference to a station. More...
struct  sla_trunk
struct  sla_trunk_ref
 A station's reference to a trunk. More...
struct  volume

Defines

#define AST_FRAME_BITS   32
#define CONF_SIZE   320
#define CONFFLAG_DONT_DENOISE   (1ULL << 33)
#define CONFFLAG_INTROMSG   (1ULL << 32)
#define CONFFLAG_NO_AUDIO_UNTIL_UP   (1ULL << 31)
#define CONFIG_FILE_NAME   "meetme.conf"
#define DATE_FORMAT   "%Y-%m-%d %H:%M:%S"
#define DEFAULT_AUDIO_BUFFERS   32
#define MAX_CONFNUM   80
#define MAX_PIN   80
#define MAX_SETTINGS   (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)
#define MC_DATA_FORMAT   "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
#define MC_HEADER_FORMAT   "%-14s %-14s %-10s %-8s %-8s %-6s\n"
#define MEETME_DATA_EXPORT(MEMBER)
#define MEETME_DELAYDETECTENDTALK   1000
#define MEETME_DELAYDETECTTALK   300
#define MEETME_USER_DATA_EXPORT(MEMBER)
#define OPTIONS_LEN   100
#define S(e)   case e: return # e;
#define SLA_CONFIG_FILE   "sla.conf"
#define STR_CONCISE   "concise"

Enumerations

enum  { ADMINFLAG_MUTED = (1 << 1), ADMINFLAG_SELFMUTED = (1 << 2), ADMINFLAG_KICKME = (1 << 3), ADMINFLAG_T_REQUEST = (1 << 4) }
enum  {
  CONFFLAG_ADMIN = (1 << 0), CONFFLAG_MONITOR = (1 << 1), CONFFLAG_KEYEXIT = (1 << 2), CONFFLAG_STARMENU = (1 << 3),
  CONFFLAG_TALKER = (1 << 4), CONFFLAG_QUIET = (1 << 5), CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6), CONFFLAG_AGI = (1 << 7),
  CONFFLAG_MOH = (1 << 8), CONFFLAG_MARKEDEXIT = (1 << 9), CONFFLAG_WAITMARKED = (1 << 10), CONFFLAG_EXIT_CONTEXT = (1 << 11),
  CONFFLAG_MARKEDUSER = (1 << 12), CONFFLAG_INTROUSER = (1 << 13), CONFFLAG_RECORDCONF = (1<< 14), CONFFLAG_MONITORTALKER = (1 << 15),
  CONFFLAG_DYNAMIC = (1 << 16), CONFFLAG_DYNAMICPIN = (1 << 17), CONFFLAG_EMPTY = (1 << 18), CONFFLAG_EMPTYNOPIN = (1 << 19),
  CONFFLAG_ALWAYSPROMPT = (1 << 20), CONFFLAG_OPTIMIZETALKER = (1 << 21), CONFFLAG_NOONLYPERSON = (1 << 22), CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
  CONFFLAG_STARTMUTED = (1 << 24), CONFFLAG_PASS_DTMF = (1 << 25), CONFFLAG_SLA_STATION = (1 << 26), CONFFLAG_SLA_TRUNK = (1 << 27),
  CONFFLAG_KICK_CONTINUE = (1 << 28), CONFFLAG_DURATION_STOP = (1 << 29), CONFFLAG_DURATION_LIMIT = (1 << 30)
}
enum  {
  OPT_ARG_WAITMARKED = 0, OPT_ARG_EXITKEYS = 1, OPT_ARG_DURATION_STOP = 2, OPT_ARG_DURATION_LIMIT = 3,
  OPT_ARG_MOH_CLASS = 4, OPT_ARG_INTROMSG = 5, OPT_ARG_ARRAY_SIZE = 6
}
enum  { SLA_TRUNK_OPT_MOH = (1 << 0) }
enum  { SLA_TRUNK_OPT_ARG_MOH_CLASS = 0, SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1 }
enum  announcetypes { CONF_HASJOIN, CONF_HASLEFT }
enum  entrance_sound { ENTER, LEAVE }
enum  menu_modes { MENU_DISABLED = 0, MENU_NORMAL, MENU_ADMIN, MENU_ADMIN_EXTENDED }
enum  recording_state { MEETME_RECORD_OFF, MEETME_RECORD_STARTED, MEETME_RECORD_ACTIVE, MEETME_RECORD_TERMINATE }
enum  sla_event_type { SLA_EVENT_HOLD, SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK }
 

Event types that can be queued up for the SLA thread.

More...
enum  sla_hold_access { SLA_HOLD_OPEN, SLA_HOLD_PRIVATE }
enum  sla_station_hangup { SLA_STATION_HANGUP_NORMAL, SLA_STATION_HANGUP_TIMEOUT }
enum  sla_trunk_state {
  SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, SLA_TRUNK_STATE_ONHOLD,
  SLA_TRUNK_STATE_ONHOLD_BYME
}
enum  sla_which_trunk_refs { ALL_TRUNK_REFS, INACTIVE_TRUNK_REFS }
enum  volume_action { VOL_UP, VOL_DOWN }

Functions

static int acf_meetme_info (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_meetme_info_eval (const char *keyword, const struct ast_conference *conf)
static int action_meetmelist (struct mansession *s, const struct message *m)
static int action_meetmemute (struct mansession *s, const struct message *m)
static int action_meetmeunmute (struct mansession *s, const struct message *m)
static int admin_exec (struct ast_channel *chan, const char *data)
 The MeetMeadmin application.
static void * announce_thread (void *data)
static void answer_trunk_chan (struct ast_channel *chan)
 AST_APP_OPTIONS (sla_trunk_opts, BEGIN_OPTIONS AST_APP_OPTION_ARG('M', SLA_TRUNK_OPT_MOH, SLA_TRUNK_OPT_ARG_MOH_CLASS), END_OPTIONS)
 AST_APP_OPTIONS (meetme_opts, BEGIN_OPTIONS AST_APP_OPTION('A', CONFFLAG_MARKEDUSER), AST_APP_OPTION('a', CONFFLAG_ADMIN), AST_APP_OPTION('b', CONFFLAG_AGI), AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT), AST_APP_OPTION('C', CONFFLAG_KICK_CONTINUE), AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN), AST_APP_OPTION('d', CONFFLAG_DYNAMIC), AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN), AST_APP_OPTION('e', CONFFLAG_EMPTY), AST_APP_OPTION('F', CONFFLAG_PASS_DTMF), AST_APP_OPTION_ARG('G', CONFFLAG_INTROMSG, OPT_ARG_INTROMSG), AST_APP_OPTION('i', CONFFLAG_INTROUSER), AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW), AST_APP_OPTION_ARG('M', CONFFLAG_MOH, OPT_ARG_MOH_CLASS), AST_APP_OPTION('m', CONFFLAG_STARTMUTED), AST_APP_OPTION('n', CONFFLAG_DONT_DENOISE), AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER), AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT), AST_APP_OPTION_ARG('p', CONFFLAG_KEYEXIT, OPT_ARG_EXITKEYS), AST_APP_OPTION('q', CONFFLAG_QUIET), AST_APP_OPTION('r', CONFFLAG_RECORDCONF), AST_APP_OPTION('s', CONFFLAG_STARMENU), AST_APP_OPTION('T', CONFFLAG_MONITORTALKER), AST_APP_OPTION('l', CONFFLAG_MONITOR), AST_APP_OPTION('t', CONFFLAG_TALKER), AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED), AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT), AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT), AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON), AST_APP_OPTION_ARG('S', CONFFLAG_DURATION_STOP, OPT_ARG_DURATION_STOP), AST_APP_OPTION_ARG('L', CONFFLAG_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT), END_OPTIONS)
 AST_DATA_STRUCTURE (ast_conf_user, MEETME_USER_DATA_EXPORT)
 AST_DATA_STRUCTURE (ast_conference, MEETME_DATA_EXPORT)
static AST_LIST_HEAD_STATIC (confs, ast_conference)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,"MeetMe conference bridge",.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_DEVSTATE_PROVIDER,)
static struct ast_conferencebuild_conf (const char *confno, const char *pin, const char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan, struct ast_test *test)
 Find or create a conference.
static int can_write (struct ast_channel *chan, struct ast_flags64 *confflags)
static int careful_write (int fd, unsigned char *data, int len, int block)
static int channel_admin_exec (struct ast_channel *chan, const char *data)
 The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command).
static char * complete_confno (const char *word, int state)
static char * complete_meetmecmd_list (const char *line, const char *word, int pos, int state)
static char * complete_meetmecmd_lock (const char *word, int pos, int state)
static char * complete_meetmecmd_mute_kick (const char *line, const char *word, int pos, int state)
static char * complete_userno (struct ast_conference *cnf, const char *word, int state)
static int conf_exec (struct ast_channel *chan, const char *data)
 The meetme() application.
static void conf_flush (int fd, struct ast_channel *chan)
static int conf_free (struct ast_conference *conf)
 Remove the conference from the list and free it.
static void conf_play (struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
static void conf_queue_dtmf (const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
static int conf_run (struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
static void conf_start_moh (struct ast_channel *chan, const char *musicclass)
static int count_exec (struct ast_channel *chan, const char *data)
 The MeetmeCount application.
static struct sla_trunk_refcreate_trunk_ref (struct sla_trunk *trunk)
static void * dial_trunk (void *data)
static int dispose_conf (struct ast_conference *conf)
 Decrement reference counts, as incremented by find_conf().
static void filename_parse (char *filename, char *buffer)
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags)
static struct ast_conferencefind_conf_realtime (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags, int *too_early, char **optargs)
static struct ast_conf_userfind_user (struct ast_conference *conf, const char *callerident)
static const char * get_announce_filename (enum announcetypes type)
static const char * istalking (int x)
static int load_config (int reload)
static void load_config_meetme (void)
static int load_module (void)
static char * meetme_cmd_helper (struct ast_cli_args *a)
static int meetme_data_provider_get (const struct ast_data_search *search, struct ast_data *data_root)
static char * meetme_kick_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * meetme_lock_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void meetme_menu (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size, struct dahdi_confinfo *dahdic)
static void meetme_menu_admin (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
static void meetme_menu_admin_extended (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size, struct dahdi_confinfo *dahdic)
static void meetme_menu_normal (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
static char * meetme_mute_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * meetme_show_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int meetmemute (struct mansession *s, const struct message *m, int mute)
static enum ast_device_state meetmestate (const char *data)
 Callback for devicestate providers.
static struct sla_ringing_trunkqueue_ringing_trunk (struct sla_trunk *trunk)
static void * recordthread (void *args)
static int reload (void)
static void reset_volumes (struct ast_conf_user *user)
static int rt_extend_conf (const char *confno)
static void * run_station (void *data)
static void send_talking_event (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
static int set_listen_volume (struct ast_conf_user *user, int volume)
static int set_talk_volume (struct ast_conf_user *user, int volume)
static void set_user_talking (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
static void sla_add_trunk_to_station (struct sla_station *station, struct ast_variable *var)
static int sla_build_station (struct ast_config *cfg, const char *cat)
static int sla_build_trunk (struct ast_config *cfg, const char *cat)
static int sla_calc_station_delays (unsigned int *timeout)
 Calculate the ring delay for a station.
static int sla_calc_station_timeouts (unsigned int *timeout)
 Process station ring timeouts.
static int sla_calc_trunk_timeouts (unsigned int *timeout)
 Process trunk ring timeouts.
static void sla_change_trunk_state (const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
static int sla_check_device (const char *device)
static int sla_check_failed_station (const struct sla_station *station)
 Check to see if this station has failed to be dialed in the past minute.
static int sla_check_inuse_station (const struct sla_station *station)
 Check to see if a station is in use.
static int sla_check_ringing_station (const struct sla_station *station)
 Check to see if this station is already ringing.
static int sla_check_station_delay (struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
 Calculate the ring delay for a given ringing trunk on a station.
static int sla_check_station_hold_access (const struct sla_trunk *trunk, const struct sla_station *station)
static int sla_check_timed_out_station (const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
 Check to see if dialing this station already timed out for this ringing trunk.
static struct sla_trunk_refsla_choose_idle_trunk (const struct sla_station *station)
 For a given station, choose the highest priority idle trunk.
static struct sla_ringing_trunksla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int rm)
 Choose the highest priority ringing trunk for a station.
static struct sla_failed_stationsla_create_failed_station (struct sla_station *station)
static struct sla_ringing_stationsla_create_ringing_station (struct sla_station *station)
static struct sla_station_refsla_create_station_ref (struct sla_station *station)
static void sla_destroy (void)
static void sla_dial_state_callback (struct ast_dial *dial)
static void sla_event_destroy (struct sla_event *event)
static void sla_failed_station_destroy (struct sla_failed_station *failed_station)
static struct sla_stationsla_find_station (const char *name)
static struct sla_trunksla_find_trunk (const char *name)
static struct sla_trunk_refsla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk)
static struct sla_trunk_refsla_find_trunk_ref_byname (const struct sla_station *station, const char *name)
 Find a trunk reference on a station by name.
static void sla_handle_dial_state_event (void)
static void sla_handle_hold_event (struct sla_event *event)
static void sla_handle_ringing_trunk_event (void)
static void sla_hangup_stations (void)
static const char * sla_hold_str (unsigned int hold_access)
static int sla_in_use (void)
static int sla_load_config (int reload)
static int sla_process_timers (struct timespec *ts)
 Calculate the time until the next known event.
static void sla_queue_event (enum sla_event_type type)
static void sla_queue_event_conf (enum sla_event_type type, struct ast_channel *chan, struct ast_conference *conf)
 Queue a SLA event from the conference.
static void sla_queue_event_full (enum sla_event_type type, struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
static void sla_queue_event_nolock (enum sla_event_type type)
static int sla_ring_station (struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
 Ring a station.
static void sla_ring_stations (void)
 Ring stations based on current set of ringing trunks.
static void sla_ringing_station_destroy (struct sla_ringing_station *ringing_station)
static void sla_ringing_trunk_destroy (struct sla_ringing_trunk *ringing_trunk)
static char * sla_show_stations (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * sla_show_trunks (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static enum ast_device_state sla_state (const char *data)
static enum ast_device_state sla_state_to_devstate (enum sla_trunk_state state)
static int sla_station_cmp (void *obj, void *arg, int flags)
static void sla_station_destructor (void *obj)
static int sla_station_exec (struct ast_channel *chan, const char *data)
static int sla_station_hash (const void *obj, const int flags)
static int sla_station_is_marked (void *obj, void *arg, int flags)
static int sla_station_mark (void *obj, void *arg, int flags)
static void sla_station_ref_destructor (void *obj)
static int sla_station_release_refs (void *obj, void *arg, int flags)
static void sla_stop_ringing_station (struct sla_ringing_station *ringing_station, enum sla_station_hangup hangup)
static void sla_stop_ringing_trunk (struct sla_ringing_trunk *ringing_trunk)
static void * sla_thread (void *data)
static int sla_trunk_cmp (void *obj, void *arg, int flags)
static void sla_trunk_destructor (void *obj)
static int sla_trunk_exec (struct ast_channel *chan, const char *data)
static int sla_trunk_hash (const void *obj, const int flags)
static int sla_trunk_is_marked (void *obj, void *arg, int flags)
static int sla_trunk_mark (void *obj, void *arg, int flags)
static void sla_trunk_ref_destructor (void *obj)
static int sla_trunk_release_refs (void *obj, void *arg, int flags)
static const char * trunkstate2str (enum sla_trunk_state state)
static void tweak_listen_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_talk_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_volume (struct volume *vol, enum volume_action action)
static int unload_module (void)
static int user_add_provider_cb (void *obj, void *arg, int flags)
static int user_chan_cb (void *obj, void *args, int flags)
static int user_listen_voldown_cb (void *obj, void *unused, int flags)
static int user_listen_volup_cb (void *obj, void *unused, int flags)
static int user_max_cmp (void *obj, void *arg, int flags)
static int user_no_cmp (void *obj, void *arg, int flags)
static int user_reset_vol_cb (void *obj, void *unused, int flags)
static int user_set_kickme_cb (void *obj, void *check_admin_arg, int flags)
static int user_set_muted_cb (void *obj, void *check_admin_arg, int flags)
static int user_set_unmuted_cb (void *obj, void *check_admin_arg, int flags)
static int user_talk_voldown_cb (void *obj, void *unused, int flags)
static int user_talk_volup_cb (void *obj, void *unused, int flags)

Variables

static const char *const app = "MeetMe"
static const char *const app2 = "MeetMeCount"
static const char *const app3 = "MeetMeAdmin"
static const char *const app4 = "MeetMeChannelAdmin"
static int audio_buffers
 The number of audio buffers to be allocated on pseudo channels when in a conference.
static struct ast_cli_entry cli_meetme []
static unsigned int conf_map [1024] = {0, }
static int earlyalert
static int endalert
static int extendby
static int fuzzystart
static const char gain_map []
 Map 'volume' levels from -5 through +5 into decibel (dB) settings for channel drivers.
static struct ast_data_handler meetme_data_provider
static struct ast_data_entry meetme_data_providers []
static struct ast_custom_function meetme_info_acf
static int rt_log_members
static int rt_schedule
struct {
   ast_cond_t   cond
   ast_mutex_t   lock
   pthread_t   thread
sla
 A structure for data used by the sla thread.
static const char sla_registrar [] = "SLA"
static struct ao2_containersla_stations
static struct ao2_containersla_trunks
static const char *const slastation_app = "SLAStation"
static const char *const slatrunk_app = "SLATrunk"

Detailed Description

Meet me conference bridge and Shared Line Appearances.

Author:
Mark Spencer <markster@digium.com>
(SLA) Russell Bryant <russell@digium.com>

Definition in file app_meetme.c.


Define Documentation

#define AST_FRAME_BITS   32

Definition at line 545 of file app_meetme.c.

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

#define CONF_SIZE   320

Definition at line 564 of file app_meetme.c.

#define CONFFLAG_DONT_DENOISE   (1ULL << 33)

If set, don't enable a denoiser for the channel

Definition at line 630 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_INTROMSG   (1ULL << 32)

If set play an intro announcement at start of conference

Definition at line 628 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_NO_AUDIO_UNTIL_UP   (1ULL << 31)

Do not write any audio to this channel until the state is up.

Definition at line 626 of file app_meetme.c.

Referenced by can_write(), conf_run(), and sla_trunk_exec().

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 524 of file app_meetme.c.

Referenced by _dsp_init(), conf_exec(), find_conf(), and load_config_meetme().

#define DATE_FORMAT   "%Y-%m-%d %H:%M:%S"

String format for scheduled conferences

Definition at line 532 of file app_meetme.c.

Referenced by append_date(), build_radius_record(), conf_run(), execute_cb(), find_conf_realtime(), format_date(), get_date(), manager_log(), pgsql_log(), and rt_extend_conf().

#define DEFAULT_AUDIO_BUFFERS   32

each buffer is 20ms, so this is 640ms total

Definition at line 529 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80
#define MAX_PIN   80

Definition at line 694 of file app_meetme.c.

Referenced by conf_exec().

#define MAX_SETTINGS   (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)

Definition at line 698 of file app_meetme.c.

Referenced by conf_exec(), and find_conf().

#define MC_DATA_FORMAT   "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"

Referenced by meetme_show_cmd().

#define MC_HEADER_FORMAT   "%-14s %-14s %-10s %-8s %-8s %-6s\n"

Referenced by meetme_show_cmd().

#define MEETME_DATA_EXPORT ( MEMBER   ) 

Definition at line 7527 of file app_meetme.c.

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 543 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 542 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_USER_DATA_EXPORT ( MEMBER   ) 

Definition at line 7544 of file app_meetme.c.

#define OPTIONS_LEN   100

Definition at line 695 of file app_meetme.c.

Referenced by find_conf_realtime().

#define S (  )     case e: return # e;

Referenced by sms_readfile(), and trunkstate2str().

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 525 of file app_meetme.c.

Referenced by sla_build_station(), sla_build_trunk(), and sla_load_config().

#define STR_CONCISE   "concise"

Definition at line 526 of file app_meetme.c.

Referenced by complete_meetmecmd_list(), and meetme_show_cmd().


Enumeration Type Documentation

anonymous enum
Enumerator:
ADMINFLAG_MUTED 

User is muted

ADMINFLAG_SELFMUTED 

User muted self

ADMINFLAG_KICKME 

User has been kicked

ADMINFLAG_T_REQUEST 

User has requested to speak

Definition at line 534 of file app_meetme.c.

00534      {
00535    ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
00536    ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
00537    ADMINFLAG_KICKME =    (1 << 3),  /*!< User has been kicked */
00538    /*! User has requested to speak */
00539    ADMINFLAG_T_REQUEST = (1 << 4),
00540 };

anonymous enum
Enumerator:
CONFFLAG_ADMIN 

user has admin access on the conference

CONFFLAG_MONITOR 

If set the user can only receive audio from the conference

CONFFLAG_KEYEXIT 

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

CONFFLAG_STARMENU 

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

CONFFLAG_TALKER 

If set the use can only send audio to the conference

CONFFLAG_QUIET 

If set there will be no enter or leave sounds

CONFFLAG_ANNOUNCEUSERCOUNT 

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

CONFFLAG_AGI 

Set to run AGI Script in Background

CONFFLAG_MOH 

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

CONFFLAG_MARKEDEXIT 

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

CONFFLAG_WAITMARKED 

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

CONFFLAG_EXIT_CONTEXT 

If set, the MeetMe will exit to the specified context

CONFFLAG_MARKEDUSER 

If set, the user will be marked

CONFFLAG_INTROUSER 

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

CONFFLAG_RECORDCONF 

If set, the MeetMe will be recorded

CONFFLAG_MONITORTALKER 

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

CONFFLAG_DYNAMIC 
CONFFLAG_DYNAMICPIN 
CONFFLAG_EMPTY 
CONFFLAG_EMPTYNOPIN 
CONFFLAG_ALWAYSPROMPT 
CONFFLAG_OPTIMIZETALKER 

If set, treat talking users as muted users

CONFFLAG_NOONLYPERSON 

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

CONFFLAG_INTROUSERNOREVIEW 

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

CONFFLAG_STARTMUTED 

If set, the user will be initially self-muted

CONFFLAG_PASS_DTMF 

Pass DTMF through the conference

CONFFLAG_SLA_STATION 
CONFFLAG_SLA_TRUNK 
CONFFLAG_KICK_CONTINUE 

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

CONFFLAG_DURATION_STOP 
CONFFLAG_DURATION_LIMIT 

Definition at line 566 of file app_meetme.c.

00566      {
00567    /*! user has admin access on the conference */
00568    CONFFLAG_ADMIN = (1 << 0),
00569    /*! If set the user can only receive audio from the conference */
00570    CONFFLAG_MONITOR = (1 << 1),
00571    /*! If set asterisk will exit conference when key defined in p() option is pressed */
00572    CONFFLAG_KEYEXIT = (1 << 2),
00573    /*! If set asterisk will provide a menu to the user when '*' is pressed */
00574    CONFFLAG_STARMENU = (1 << 3),
00575    /*! If set the use can only send audio to the conference */
00576    CONFFLAG_TALKER = (1 << 4),
00577    /*! If set there will be no enter or leave sounds */
00578    CONFFLAG_QUIET = (1 << 5),
00579    /*! If set, when user joins the conference, they will be told the number 
00580     *  of users that are already in */
00581    CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
00582    /*! Set to run AGI Script in Background */
00583    CONFFLAG_AGI = (1 << 7),
00584    /*! Set to have music on hold when user is alone in conference */
00585    CONFFLAG_MOH = (1 << 8),
00586    /*! If set, the channel will leave the conference if all marked users leave */
00587    CONFFLAG_MARKEDEXIT = (1 << 9),
00588    /*! If set, the MeetMe will wait until a marked user enters */
00589    CONFFLAG_WAITMARKED = (1 << 10),
00590    /*! If set, the MeetMe will exit to the specified context */
00591    CONFFLAG_EXIT_CONTEXT = (1 << 11),
00592    /*! If set, the user will be marked */
00593    CONFFLAG_MARKEDUSER = (1 << 12),
00594    /*! If set, user will be ask record name on entry of conference */
00595    CONFFLAG_INTROUSER = (1 << 13),
00596    /*! If set, the MeetMe will be recorded */
00597    CONFFLAG_RECORDCONF = (1<< 14),
00598    /*! If set, the user will be monitored if the user is talking or not */
00599    CONFFLAG_MONITORTALKER = (1 << 15),
00600    CONFFLAG_DYNAMIC = (1 << 16),
00601    CONFFLAG_DYNAMICPIN = (1 << 17),
00602    CONFFLAG_EMPTY = (1 << 18),
00603    CONFFLAG_EMPTYNOPIN = (1 << 19),
00604    CONFFLAG_ALWAYSPROMPT = (1 << 20),
00605    /*! If set, treat talking users as muted users */
00606    CONFFLAG_OPTIMIZETALKER = (1 << 21),
00607    /*! If set, won't speak the extra prompt when the first person 
00608     *  enters the conference */
00609    CONFFLAG_NOONLYPERSON = (1 << 22),
00610    /*! If set, user will be asked to record name on entry of conference 
00611     *  without review */
00612    CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
00613    /*! If set, the user will be initially self-muted */
00614    CONFFLAG_STARTMUTED = (1 << 24),
00615    /*! Pass DTMF through the conference */
00616    CONFFLAG_PASS_DTMF = (1 << 25),
00617    CONFFLAG_SLA_STATION = (1 << 26),
00618    CONFFLAG_SLA_TRUNK = (1 << 27),
00619    /*! If set, the user should continue in the dialplan if kicked out */
00620    CONFFLAG_KICK_CONTINUE = (1 << 28),
00621    CONFFLAG_DURATION_STOP = (1 << 29),
00622    CONFFLAG_DURATION_LIMIT = (1 << 30),
00623 };

anonymous enum
Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_EXITKEYS 
OPT_ARG_DURATION_STOP 
OPT_ARG_DURATION_LIMIT 
OPT_ARG_MOH_CLASS 
OPT_ARG_INTROMSG 
OPT_ARG_ARRAY_SIZE 

Definition at line 632 of file app_meetme.c.

00632      {
00633    OPT_ARG_WAITMARKED = 0,
00634    OPT_ARG_EXITKEYS   = 1,
00635    OPT_ARG_DURATION_STOP = 2,
00636    OPT_ARG_DURATION_LIMIT = 3,
00637    OPT_ARG_MOH_CLASS = 4,
00638    OPT_ARG_INTROMSG = 5,
00639    OPT_ARG_ARRAY_SIZE = 6,
00640 };

anonymous enum
Enumerator:
SLA_TRUNK_OPT_MOH 

Definition at line 6724 of file app_meetme.c.

06724      {
06725    SLA_TRUNK_OPT_MOH = (1 << 0),
06726 };

anonymous enum
Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 6728 of file app_meetme.c.

06728      {
06729    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
06730    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
06731 };

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 700 of file app_meetme.c.

00700                    {
00701    CONF_HASJOIN,
00702    CONF_HASLEFT
00703 };

Enumerator:
ENTER 
LEAVE 

Definition at line 552 of file app_meetme.c.

00552                     {
00553    ENTER,
00554    LEAVE
00555 };

enum menu_modes
Enumerator:
MENU_DISABLED 
MENU_NORMAL 
MENU_ADMIN 
MENU_ADMIN_EXTENDED 

Definition at line 2332 of file app_meetme.c.

02332                 {
02333    MENU_DISABLED = 0,
02334    MENU_NORMAL,
02335    MENU_ADMIN,
02336    MENU_ADMIN_EXTENDED,
02337 };

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 557 of file app_meetme.c.

Event types that can be queued up for the SLA thread.

Enumerator:
SLA_EVENT_HOLD 

A station has put the call on hold

SLA_EVENT_DIAL_STATE 

The state of a dial has changed

SLA_EVENT_RINGING_TRUNK 

The state of a ringing trunk has changed

Definition at line 911 of file app_meetme.c.

00911                     {
00912    /*! A station has put the call on hold */
00913    SLA_EVENT_HOLD,
00914    /*! The state of a dial has changed */
00915    SLA_EVENT_DIAL_STATE,
00916    /*! The state of a ringing trunk has changed */
00917    SLA_EVENT_RINGING_TRUNK,
00918 };

Enumerator:
SLA_HOLD_OPEN 

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

SLA_HOLD_PRIVATE 

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

Definition at line 804 of file app_meetme.c.

00804                      {
00805    /*! This means that any station can put it on hold, and any station
00806     * can retrieve the call from hold. */
00807    SLA_HOLD_OPEN,
00808    /*! This means that only the station that put the call on hold may
00809     * retrieve it from hold. */
00810    SLA_HOLD_PRIVATE,
00811 };

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 944 of file app_meetme.c.

Enumerator:
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 796 of file app_meetme.c.

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 791 of file app_meetme.c.

00791                           {
00792    ALL_TRUNK_REFS,
00793    INACTIVE_TRUNK_REFS,
00794 };

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 547 of file app_meetme.c.

00547                    {
00548    VOL_UP,
00549    VOL_DOWN
00550 };


Function Documentation

static int acf_meetme_info ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 7464 of file app_meetme.c.

References acf_meetme_info_eval(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_conference::confno, LOG_ERROR, LOG_NOTICE, and parse().

07465 {
07466    struct ast_conference *conf;
07467    char *parse;
07468    int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
07469    AST_DECLARE_APP_ARGS(args,
07470       AST_APP_ARG(keyword);
07471       AST_APP_ARG(confno);
07472    );
07473 
07474    if (ast_strlen_zero(data)) {
07475       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
07476       return -1;
07477    }
07478 
07479    parse = ast_strdupa(data);
07480    AST_STANDARD_APP_ARGS(args, parse);
07481 
07482    if (ast_strlen_zero(args.keyword)) {
07483       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
07484       return -1;
07485    }
07486 
07487    if (ast_strlen_zero(args.confno)) {
07488       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
07489       return -1;
07490    }
07491 
07492    AST_LIST_LOCK(&confs);
07493    AST_LIST_TRAVERSE(&confs, conf, list) {
07494       if (!strcmp(args.confno, conf->confno)) {
07495          result = acf_meetme_info_eval(args.keyword, conf);
07496          break;
07497       }
07498    }
07499    AST_LIST_UNLOCK(&confs);
07500 
07501    if (result > -1) {
07502       snprintf(buf, len, "%d", result);
07503    } else if (result == -1) {
07504       ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
07505       snprintf(buf, len, "0");
07506    } else if (result == -2) {
07507       ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno); 
07508       snprintf(buf, len, "0");
07509    }
07510 
07511    return 0;
07512 }

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

Definition at line 7446 of file app_meetme.c.

References ast_conference::isdynamic, ast_conference::locked, ast_conference::start, and ast_conference::users.

Referenced by acf_meetme_info().

07447 {
07448    if (!strcasecmp("lock", keyword)) {
07449       return conf->locked;
07450    } else if (!strcasecmp("parties", keyword)) {
07451       return conf->users;
07452    } else if (!strcasecmp("activity", keyword)) {
07453       time_t now;
07454       now = time(NULL);
07455       return (now - conf->start);
07456    } else if (!strcasecmp("dynamic", keyword)) {
07457       return conf->isdynamic;
07458    } else {
07459       return -1;
07460    }
07461 
07462 }

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

Definition at line 5091 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag64, astman_append(), astman_get_header(), astman_send_error(), astman_send_listack(), ast_channel::caller, ast_conf_user::chan, CONFFLAG_ADMIN, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_conference::confno, ast_channel::connected, ast_party_connected_line::id, ast_party_caller::id, ast_party_id::name, ast_party_id::number, S_COR, ast_party_name::str, ast_party_number::str, ast_conf_user::talking, total, ast_conf_user::user_no, ast_conference::usercontainer, ast_conf_user::userflags, ast_party_name::valid, and ast_party_number::valid.

Referenced by load_module().

05092 {
05093    const char *actionid = astman_get_header(m, "ActionID");
05094    const char *conference = astman_get_header(m, "Conference");
05095    char idText[80] = "";
05096    struct ast_conference *cnf;
05097    struct ast_conf_user *user;
05098    struct ao2_iterator user_iter;
05099    int total = 0;
05100 
05101    if (!ast_strlen_zero(actionid))
05102       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
05103 
05104    if (AST_LIST_EMPTY(&confs)) {
05105       astman_send_error(s, m, "No active conferences.");
05106       return 0;
05107    }
05108 
05109    astman_send_listack(s, m, "Meetme user list will follow", "start");
05110 
05111    /* Find the right conference */
05112    AST_LIST_LOCK(&confs);
05113    AST_LIST_TRAVERSE(&confs, cnf, list) {
05114       /* If we ask for one particular, and this isn't it, skip it */
05115       if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
05116          continue;
05117 
05118       /* Show all the users */
05119       user_iter = ao2_iterator_init(cnf->usercontainer, 0);
05120       while ((user = ao2_iterator_next(&user_iter))) {
05121          total++;
05122          astman_append(s,
05123             "Event: MeetmeList\r\n"
05124             "%s"
05125             "Conference: %s\r\n"
05126             "UserNumber: %d\r\n"
05127             "CallerIDNum: %s\r\n"
05128             "CallerIDName: %s\r\n"
05129             "ConnectedLineNum: %s\r\n"
05130             "ConnectedLineName: %s\r\n"
05131             "Channel: %s\r\n"
05132             "Admin: %s\r\n"
05133             "Role: %s\r\n"
05134             "MarkedUser: %s\r\n"
05135             "Muted: %s\r\n"
05136             "Talking: %s\r\n"
05137             "\r\n",
05138             idText,
05139             cnf->confno,
05140             user->user_no,
05141             S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
05142             S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
05143             S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
05144             S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<no name>"),
05145             user->chan->name,
05146             ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
05147             ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
05148             ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
05149             user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
05150             user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
05151          ao2_ref(user, -1);
05152       }
05153       ao2_iterator_destroy(&user_iter);
05154    }
05155    AST_LIST_UNLOCK(&confs);
05156    /* Send final confirmation */
05157    astman_append(s,
05158    "Event: MeetmeListComplete\r\n"
05159    "EventList: Complete\r\n"
05160    "ListItems: %d\r\n"
05161    "%s"
05162    "\r\n", total, idText);
05163    return 0;
05164 }

static int action_meetmemute ( struct mansession s,
const struct message m 
) [static]

Definition at line 5081 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

05082 {
05083    return meetmemute(s, m, 1);
05084 }

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

Definition at line 5086 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

05087 {
05088    return meetmemute(s, m, 0);
05089 }

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

The MeetMeadmin application.

MeetMeAdmin(confno, command, caller)

Definition at line 4793 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ao2_callback, ao2_find, ao2_ref, args, AST_APP_ARG, ast_atomic_fetchadd_int(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag64, CONFFLAG_ADMIN, ast_conference::confno, dispose_conf(), find_user(), ast_conference::locked, LOG_NOTICE, LOG_WARNING, OBJ_NODATA, pbx_builtin_setvar_helper(), ast_conference::refcount, reset_volumes(), rt_extend_conf(), tweak_listen_volume(), tweak_talk_volume(), user_listen_voldown_cb(), user_listen_volup_cb(), user_max_cmp(), user_reset_vol_cb(), user_set_kickme_cb(), user_set_muted_cb(), user_set_unmuted_cb(), user_talk_voldown_cb(), user_talk_volup_cb(), ast_conference::usercontainer, ast_conf_user::userflags, VOL_DOWN, and VOL_UP.

Referenced by load_module(), meetme_cmd_helper(), run_station(), sla_station_exec(), and sla_stop_ringing_trunk().

04793                                                                   {
04794    char *params;
04795    struct ast_conference *cnf;
04796    struct ast_conf_user *user = NULL;
04797    AST_DECLARE_APP_ARGS(args,
04798       AST_APP_ARG(confno);
04799       AST_APP_ARG(command);
04800       AST_APP_ARG(user);
04801    );
04802    int res = 0;
04803 
04804    if (ast_strlen_zero(data)) {
04805       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
04806       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04807       return -1;
04808    }
04809 
04810    params = ast_strdupa(data);
04811    AST_STANDARD_APP_ARGS(args, params);
04812 
04813    if (!args.command) {
04814       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
04815       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04816       return -1;
04817    }
04818 
04819    AST_LIST_LOCK(&confs);
04820    AST_LIST_TRAVERSE(&confs, cnf, list) {
04821       if (!strcmp(cnf->confno, args.confno))
04822          break;
04823    }
04824 
04825    if (!cnf) {
04826       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
04827       AST_LIST_UNLOCK(&confs);
04828       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
04829       return 0;
04830    }
04831 
04832    ast_atomic_fetchadd_int(&cnf->refcount, 1);
04833 
04834    if (args.user) {
04835       user = find_user(cnf, args.user);
04836       if (!user) {
04837          ast_log(LOG_NOTICE, "Specified User not found!\n");
04838          res = -2;
04839          goto usernotfound;
04840       }
04841    } else {
04842       /* fail for commands that require a user */
04843       switch (*args.command) {
04844       case 'm': /* Unmute */
04845       case 'M': /* Mute */
04846       case 't': /* Lower user's talk volume */
04847       case 'T': /* Raise user's talk volume */
04848       case 'u': /* Lower user's listen volume */
04849       case 'U': /* Raise user's listen volume */
04850       case 'r': /* Reset user's volume level */
04851       case 'k': /* Kick user */
04852          res = -2;
04853          ast_log(LOG_NOTICE, "No user specified!\n");
04854          goto usernotfound;
04855       default:
04856          break;
04857       }
04858    }
04859 
04860    switch (*args.command) {
04861    case 76: /* L: Lock */ 
04862       cnf->locked = 1;
04863       break;
04864    case 108: /* l: Unlock */ 
04865       cnf->locked = 0;
04866       break;
04867    case 75: /* K: kick all users */
04868       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_kickme_cb, NULL);
04869       break;
04870    case 101: /* e: Eject last user*/
04871    {
04872       int max_no = 0;
04873       struct ast_conf_user *eject_user;
04874 
04875       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
04876       eject_user = ao2_find(cnf->usercontainer, &max_no, 0);
04877       if (!eject_user) {
04878          res = -1;
04879          ast_log(LOG_NOTICE, "No last user to kick!\n");
04880          break;
04881       }
04882 
04883       if (!ast_test_flag64(&eject_user->userflags, CONFFLAG_ADMIN)) {
04884          eject_user->adminflags |= ADMINFLAG_KICKME;
04885       } else {
04886          res = -1;
04887          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
04888       }
04889 
04890       ao2_ref(eject_user, -1);
04891       break;
04892    }
04893    case 77: /* M: Mute */ 
04894       user->adminflags |= ADMINFLAG_MUTED;
04895       break;
04896    case 78: /* N: Mute all (non-admin) users */
04897       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_muted_cb, &cnf);
04898       break;               
04899    case 109: /* m: Unmute */ 
04900       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04901       break;
04902    case 110: /* n: Unmute all users */
04903       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, NULL);
04904       break;
04905    case 107: /* k: Kick user */ 
04906       user->adminflags |= ADMINFLAG_KICKME;
04907       break;
04908    case 118: /* v: Lower all users listen volume */
04909       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_voldown_cb, NULL);
04910       break;
04911    case 86: /* V: Raise all users listen volume */
04912       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_volup_cb, NULL);
04913       break;
04914    case 115: /* s: Lower all users speaking volume */
04915       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_voldown_cb, NULL);
04916       break;
04917    case 83: /* S: Raise all users speaking volume */
04918       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_volup_cb, NULL);
04919       break;
04920    case 82: /* R: Reset all volume levels */
04921       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_reset_vol_cb, NULL);
04922       break;
04923    case 114: /* r: Reset user's volume level */
04924       reset_volumes(user);
04925       break;
04926    case 85: /* U: Raise user's listen volume */
04927       tweak_listen_volume(user, VOL_UP);
04928       break;
04929    case 117: /* u: Lower user's listen volume */
04930       tweak_listen_volume(user, VOL_DOWN);
04931       break;
04932    case 84: /* T: Raise user's talk volume */
04933       tweak_talk_volume(user, VOL_UP);
04934       break;
04935    case 116: /* t: Lower user's talk volume */
04936       tweak_talk_volume(user, VOL_DOWN);
04937       break;
04938    case 'E': /* E: Extend conference */
04939       if (rt_extend_conf(args.confno)) {
04940          res = -1;
04941       }
04942       break;
04943    }
04944 
04945    if (args.user) {
04946       /* decrement reference from find_user */
04947       ao2_ref(user, -1);
04948    }
04949 usernotfound:
04950    AST_LIST_UNLOCK(&confs);
04951 
04952    dispose_conf(cnf);
04953    pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
04954 
04955    return 0;
04956 }

static void* announce_thread ( void *  data  )  [static]

Definition at line 2208 of file app_meetme.c.

References 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, get_announce_filename(), and LOG_DEBUG.

Referenced by conf_run().

02209 {
02210    struct announce_listitem *current;
02211    struct ast_conference *conf = data;
02212    int res;
02213    char filename[PATH_MAX] = "";
02214    AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
02215    AST_LIST_HEAD_INIT_NOLOCK(&local_list);
02216 
02217    while (!conf->announcethread_stop) {
02218       ast_mutex_lock(&conf->announcelistlock);
02219       if (conf->announcethread_stop) {
02220          ast_mutex_unlock(&conf->announcelistlock);
02221          break;
02222       }
02223       if (AST_LIST_EMPTY(&conf->announcelist))
02224          ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
02225 
02226       AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
02227       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
02228 
02229       ast_mutex_unlock(&conf->announcelistlock);
02230       if (conf->announcethread_stop) {
02231          break;
02232       }
02233 
02234       for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
02235          ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
02236          if (!ast_fileexists(current->namerecloc, NULL, NULL))
02237             continue;
02238          if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
02239             if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
02240                res = ast_waitstream(current->confchan, "");
02241             if (!res) {
02242                ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
02243                if (!ast_streamfile(current->confchan, filename, current->language))
02244                   ast_waitstream(current->confchan, "");
02245             }
02246          }
02247          if (current->announcetype == CONF_HASLEFT) {
02248             ast_filedelete(current->namerecloc, NULL);
02249          }
02250       }
02251    }
02252 
02253    /* thread marked to stop, clean up */
02254    while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
02255       ast_filedelete(current->namerecloc, NULL);
02256       ao2_ref(current, -1);
02257    }
02258    return NULL;
02259 }

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

Definition at line 5571 of file app_meetme.c.

References ast_answer(), and ast_indicate().

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

05572 {
05573    ast_answer(chan);
05574    ast_indicate(chan, -1);
05575 }

AST_APP_OPTIONS ( sla_trunk_opts  ,
BEGIN_OPTIONS   AST_APP_OPTION_ARG'M', SLA_TRUNK_OPT_MOH, SLA_TRUNK_OPT_ARG_MOH_CLASS,
END_OPTIONS   
)
AST_APP_OPTIONS ( meetme_opts  ,
BEGIN_OPTIONS   AST_APP_OPTION'A', CONFFLAG_MARKEDUSER,
AST_APP_OPTION('a', CONFFLAG_ADMIN)  ,
AST_APP_OPTION('b', CONFFLAG_AGI)  ,
AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT)  ,
AST_APP_OPTION('C', CONFFLAG_KICK_CONTINUE)  ,
AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN)  ,
AST_APP_OPTION('d', CONFFLAG_DYNAMIC)  ,
AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN)  ,
AST_APP_OPTION('e', CONFFLAG_EMPTY)  ,
AST_APP_OPTION('F', CONFFLAG_PASS_DTMF)  ,
AST_APP_OPTION_ARG('G', CONFFLAG_INTROMSG, OPT_ARG_INTROMSG)  ,
AST_APP_OPTION('i', CONFFLAG_INTROUSER)  ,
AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW)  ,
AST_APP_OPTION_ARG('M', CONFFLAG_MOH, OPT_ARG_MOH_CLASS)  ,
AST_APP_OPTION('m', CONFFLAG_STARTMUTED)  ,
AST_APP_OPTION('n', CONFFLAG_DONT_DENOISE)  ,
AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER)  ,
AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT)  ,
AST_APP_OPTION_ARG('p', CONFFLAG_KEYEXIT, OPT_ARG_EXITKEYS)  ,
AST_APP_OPTION('q', CONFFLAG_QUIET)  ,
AST_APP_OPTION('r', CONFFLAG_RECORDCONF)  ,
AST_APP_OPTION('s', CONFFLAG_STARMENU)  ,
AST_APP_OPTION('T', CONFFLAG_MONITORTALKER)  ,
AST_APP_OPTION('l', CONFFLAG_MONITOR)  ,
AST_APP_OPTION('t', CONFFLAG_TALKER)  ,
AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED)  ,
AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT)  ,
AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT)  ,
AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON)  ,
AST_APP_OPTION_ARG('S', CONFFLAG_DURATION_STOP, OPT_ARG_DURATION_STOP)  ,
AST_APP_OPTION_ARG('L', CONFFLAG_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT)  ,
END_OPTIONS   
)
AST_DATA_STRUCTURE ( ast_conf_user  ,
MEETME_USER_DATA_EXPORT   
)
AST_DATA_STRUCTURE ( ast_conference  ,
MEETME_DATA_EXPORT   
)
static AST_LIST_HEAD_STATIC ( confs  ,
ast_conference   
) [static]
AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_LOAD_ORDER  ,
"MeetMe conference bridge"  ,
load = load_module,
unload = unload_module,
reload = reload,
load_pri = AST_MODPRI_DEVSTATE_PROVIDER 
)
static struct ast_conference* build_conf ( const char *  confno,
const char *  pin,
const char *  pinadmin,
int  make,
int  dynamic,
int  refcount,
const struct ast_channel chan,
struct ast_test *  test 
) [static, read]

Find or create a conference.

Parameters:
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
Returns:
A pointer to the conference struct, or NULL if it wasn't found and make or dynamic were not set.

Definition at line 1213 of file app_meetme.c.

References ao2_container_alloc, ao2_ref, 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_destroy, ast_mutex_init, AST_PTHREADT_NULL, ast_request(), ast_set_read_format(), ast_set_write_format(), ast_test_status_update, ast_verb, ast_conference::chan, conf_map, ast_conference::confno, ast_conference::dahdiconf, ast_conference::fd, ast_channel::fds, ast_conference::isdynamic, ast_conference::listenlock, LOG_WARNING, ast_conference::maxusers, ast_conference::pin, ast_conference::pinadmin, ast_conference::playlock, ast_conference::recordthread, ast_conference::recordthreadlock, ast_conference::refcount, ast_conference::start, ast_conference::uniqueid, user_no_cmp(), and ast_conference::usercontainer.

Referenced by dial_trunk(), find_conf(), find_conf_realtime(), run_station(), sla_station_exec(), and sla_trunk_exec().

01216 {
01217    struct ast_conference *cnf;
01218    struct dahdi_confinfo dahdic = { 0, };
01219    int confno_int = 0;
01220 
01221    AST_LIST_LOCK(&confs);
01222 
01223    AST_LIST_TRAVERSE(&confs, cnf, list) {
01224       if (!strcmp(confno, cnf->confno)) 
01225          break;
01226    }
01227 
01228    if (cnf || (!make && !dynamic))
01229       goto cnfout;
01230 
01231    /* Make a new one */
01232    if (!(cnf = ast_calloc(1, sizeof(*cnf))) ||
01233       !(cnf->usercontainer = ao2_container_alloc(1, NULL, user_no_cmp))) {
01234       goto cnfout;
01235    }
01236 
01237    ast_mutex_init(&cnf->playlock);
01238    ast_mutex_init(&cnf->listenlock);
01239    cnf->recordthread = AST_PTHREADT_NULL;
01240    ast_mutex_init(&cnf->recordthreadlock);
01241    cnf->announcethread = AST_PTHREADT_NULL;
01242    ast_mutex_init(&cnf->announcethreadlock);
01243    ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
01244    ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
01245    ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
01246    ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid));
01247 
01248    /* Setup a new dahdi conference */
01249    dahdic.confno = -1;
01250    dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01251    cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
01252    if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
01253       if (test) {
01254          /* if we are creating a conference for a unit test, it is not neccesary
01255           * to open a pseudo channel, so, if we fail continue creating
01256           * the conference. */
01257          ast_test_status_update(test, "Unable to open DAHDI pseudo device\n");
01258       } else {
01259          ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
01260          if (cnf->fd >= 0)
01261             close(cnf->fd);
01262          ao2_ref(cnf->usercontainer, -1);
01263          ast_mutex_destroy(&cnf->playlock);
01264          ast_mutex_destroy(&cnf->listenlock);
01265          ast_mutex_destroy(&cnf->recordthreadlock);
01266          ast_mutex_destroy(&cnf->announcethreadlock);
01267          ast_free(cnf);
01268          cnf = NULL;
01269          goto cnfout;
01270       }
01271    }
01272 
01273    cnf->dahdiconf = dahdic.confno;
01274 
01275    /* Setup a new channel for playback of audio files */
01276    cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, chan, "pseudo", NULL);
01277    if (cnf->chan) {
01278       ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
01279       ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
01280       dahdic.chan = 0;
01281       dahdic.confno = cnf->dahdiconf;
01282       dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01283       if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
01284          if (test) {
01285             ast_test_status_update(test, "Error setting conference on pseudo channel\n");
01286          }
01287          ast_log(LOG_WARNING, "Error setting conference\n");
01288          if (cnf->chan)
01289             ast_hangup(cnf->chan);
01290          else
01291             close(cnf->fd);
01292          ao2_ref(cnf->usercontainer, -1);
01293          ast_mutex_destroy(&cnf->playlock);
01294          ast_mutex_destroy(&cnf->listenlock);
01295          ast_mutex_destroy(&cnf->recordthreadlock);
01296          ast_mutex_destroy(&cnf->announcethreadlock);
01297          ast_free(cnf);
01298          cnf = NULL;
01299          goto cnfout;
01300       }
01301    }
01302 
01303    /* Fill the conference struct */
01304    cnf->start = time(NULL);
01305    cnf->maxusers = 0x7fffffff;
01306    cnf->isdynamic = dynamic ? 1 : 0;
01307    ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
01308    AST_LIST_INSERT_HEAD(&confs, cnf, list);
01309 
01310    /* Reserve conference number in map */
01311    if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01312       conf_map[confno_int] = 1;
01313    
01314 cnfout:
01315    if (cnf)
01316       ast_atomic_fetchadd_int(&cnf->refcount, refcount);
01317 
01318    AST_LIST_UNLOCK(&confs);
01319 
01320    return cnf;
01321 }

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

Definition at line 2261 of file app_meetme.c.

References ast_channel::_state, AST_STATE_UP, ast_test_flag64, and CONFFLAG_NO_AUDIO_UNTIL_UP.

Referenced by conf_run().

02262 {
02263    if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02264       return 1;
02265    }
02266 
02267    return (chan->_state == AST_STATE_UP);
02268 }

static int careful_write ( int  fd,
unsigned char *  data,
int  len,
int  block 
) [static]

Definition at line 1016 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

Referenced by conf_play(), and conf_run().

01017 {
01018    int res;
01019    int x;
01020 
01021    while (len) {
01022       if (block) {
01023          x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
01024          res = ioctl(fd, DAHDI_IOMUX, &x);
01025       } else
01026          res = 0;
01027       if (res >= 0)
01028          res = write(fd, data, len);
01029       if (res < 1) {
01030          if (errno != EAGAIN) {
01031             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
01032             return -1;
01033          } else
01034             return 0;
01035       }
01036       len -= res;
01037       data += res;
01038    }
01039 
01040    return 0;
01041 }

static int channel_admin_exec ( struct ast_channel chan,
const char *  data 
) [static]

The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command).

Definition at line 4960 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ast_conf_user::adminflags, ao2_callback, ao2_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_NOTICE, LOG_WARNING, user_chan_cb(), and ast_conference::usercontainer.

Referenced by load_module().

04960                                                                           {
04961    char *params;
04962    struct ast_conference *conf = NULL;
04963    struct ast_conf_user *user = NULL;
04964    AST_DECLARE_APP_ARGS(args,
04965       AST_APP_ARG(channel);
04966       AST_APP_ARG(command);
04967    );
04968 
04969    if (ast_strlen_zero(data)) {
04970       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
04971       return -1;
04972    }
04973    
04974    params = ast_strdupa(data);
04975    AST_STANDARD_APP_ARGS(args, params);
04976 
04977    if (!args.channel) {
04978       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
04979       return -1;
04980    }
04981 
04982    if (!args.command) {
04983       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
04984       return -1;
04985    }
04986 
04987    AST_LIST_LOCK(&confs);
04988    AST_LIST_TRAVERSE(&confs, conf, list) {
04989       if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
04990          break;
04991       }
04992    }
04993    
04994    if (!user) {
04995       ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
04996       AST_LIST_UNLOCK(&confs);
04997       return 0;
04998    }
04999    
05000    /* perform the specified action */
05001    switch (*args.command) {
05002       case 77: /* M: Mute */ 
05003          user->adminflags |= ADMINFLAG_MUTED;
05004          break;
05005       case 109: /* m: Unmute */ 
05006          user->adminflags &= ~ADMINFLAG_MUTED;
05007          break;
05008       case 107: /* k: Kick user */ 
05009          user->adminflags |= ADMINFLAG_KICKME;
05010          break;
05011       default: /* unknown command */
05012          ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
05013          break;
05014    }
05015    ao2_ref(user, -1);
05016    AST_LIST_UNLOCK(&confs);
05017    
05018    return 0;
05019 }

static char* complete_confno ( const char *  word,
int  state 
) [static]

Definition at line 1323 of file app_meetme.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_conference::confno, and len().

Referenced by complete_meetmecmd_list(), complete_meetmecmd_lock(), and complete_meetmecmd_mute_kick().

01324 {
01325    struct ast_conference *cnf;
01326    char *ret = NULL;
01327    int which = 0;
01328    int len = strlen(word);
01329 
01330    AST_LIST_LOCK(&confs);
01331    AST_LIST_TRAVERSE(&confs, cnf, list) {
01332       if (!strncmp(word, cnf->confno, len) && ++which > state) {
01333          /* dup before releasing the lock */
01334          ret = ast_strdup(cnf->confno);
01335          break;
01336       }
01337    }
01338    AST_LIST_UNLOCK(&confs);
01339    return ret;
01340 }

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

Definition at line 1412 of file app_meetme.c.

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

Referenced by meetme_show_cmd().

01413 {
01414    int len;
01415 
01416    if (pos == 2) {
01417       len = strlen(word);
01418       if (!strncasecmp(word, STR_CONCISE, len)) {
01419          if (state == 0) {
01420             return ast_strdup(STR_CONCISE);
01421          }
01422          --state;
01423       }
01424 
01425       return complete_confno(word, state);
01426    }
01427    if (pos == 3 && state == 0) {
01428       char *saved = NULL;
01429       char *myline;
01430       char *confno;
01431 
01432       /* Extract the confno from the command line. */
01433       myline = ast_strdupa(line);
01434       strtok_r(myline, " ", &saved);
01435       strtok_r(NULL, " ", &saved);
01436       confno = strtok_r(NULL, " ", &saved);
01437 
01438       if (!strcasecmp(confno, STR_CONCISE)) {
01439          /* There is nothing valid in this position now. */
01440          return NULL;
01441       }
01442 
01443       len = strlen(word);
01444       if (!strncasecmp(word, STR_CONCISE, len)) {
01445          return ast_strdup(STR_CONCISE);
01446       }
01447    }
01448    return NULL;
01449 }

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

Definition at line 1404 of file app_meetme.c.

References complete_confno().

Referenced by meetme_lock_cmd().

01405 {
01406    if (pos == 2) {
01407       return complete_confno(word, state);
01408    }
01409    return NULL;
01410 }

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

Definition at line 1364 of file app_meetme.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_strdupa, complete_confno(), complete_userno(), ast_conference::confno, and len().

Referenced by meetme_kick_cmd(), and meetme_mute_cmd().

01365 {
01366    if (pos == 2) {
01367       return complete_confno(word, state);
01368    }
01369    if (pos == 3) {
01370       int len = strlen(word);
01371       char *ret = NULL;
01372       char *saved = NULL;
01373       char *myline;
01374       char *confno;
01375       struct ast_conference *cnf;
01376 
01377       if (!strncasecmp(word, "all", len)) {
01378          if (state == 0) {
01379             return ast_strdup("all");
01380          }
01381          --state;
01382       }
01383 
01384       /* Extract the confno from the command line. */
01385       myline = ast_strdupa(line);
01386       strtok_r(myline, " ", &saved);
01387       strtok_r(NULL, " ", &saved);
01388       confno = strtok_r(NULL, " ", &saved);
01389 
01390       AST_LIST_LOCK(&confs);
01391       AST_LIST_TRAVERSE(&confs, cnf, list) {
01392          if (!strcmp(confno, cnf->confno)) {
01393             ret = complete_userno(cnf, word, state);
01394             break;
01395          }
01396       }
01397       AST_LIST_UNLOCK(&confs);
01398 
01399       return ret;
01400    }
01401    return NULL;
01402 }

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

Definition at line 1342 of file app_meetme.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_strdup, len(), ast_conf_user::user_no, and ast_conference::usercontainer.

Referenced by complete_meetmecmd_mute_kick().

01343 {
01344    char usrno[50];
01345    struct ao2_iterator iter;
01346    struct ast_conf_user *usr;
01347    char *ret = NULL;
01348    int which = 0;
01349    int len = strlen(word);
01350 
01351    iter = ao2_iterator_init(cnf->usercontainer, 0);
01352    for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) {
01353       snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
01354       if (!strncmp(word, usrno, len) && ++which > state) {
01355          ao2_ref(usr, -1);
01356          ret = ast_strdup(usrno);
01357          break;
01358       }
01359    }
01360    ao2_iterator_destroy(&iter);
01361    return ret;
01362 }

static int conf_exec ( struct ast_channel chan,
const char *  data 
) [static]

The meetme() application.

Definition at line 4405 of file app_meetme.c.

References ast_channel::_state, ast_conference::adminopts, args, ARRAY_LEN, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options64(), ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime_multientry(), ast_log(), ast_say_digits(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag64, ast_test_suite_event_notify, ast_variable_browse(), ast_variable_retrieve(), ast_verb, ast_waitstream(), conf_map, conf_run(), CONFFLAG_ADMIN, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFFLAG_QUIET, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), ast_conference::isdynamic, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, MAX_SETTINGS, ast_variable::name, ast_variable::next, OPT_ARG_ARRAY_SIZE, parse(), ast_conference::pin, ast_conference::pinadmin, ast_conference::recordingfilename, ast_conference::recordingformat, SENTINEL, ast_conference::useropts, ast_conference::users, ast_variable::value, and var.

Referenced by load_module().

04406 {
04407    int res = -1;
04408    char confno[MAX_CONFNUM] = "";
04409    int allowretry = 0;
04410    int retrycnt = 0;
04411    struct ast_conference *cnf = NULL;
04412    struct ast_flags64 confflags = {0};
04413    struct ast_flags config_flags = { 0 };
04414    int dynamic = 0;
04415    int empty = 0, empty_no_pin = 0;
04416    int always_prompt = 0;
04417    const char *notdata;
04418    char *info, the_pin[MAX_PIN] = "";
04419    AST_DECLARE_APP_ARGS(args,
04420       AST_APP_ARG(confno);
04421       AST_APP_ARG(options);
04422       AST_APP_ARG(pin);
04423    );
04424    char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
04425 
04426    if (ast_strlen_zero(data)) {
04427       allowretry = 1;
04428       notdata = "";
04429    } else {
04430       notdata = data;
04431    }
04432    
04433    if (chan->_state != AST_STATE_UP)
04434       ast_answer(chan);
04435 
04436    info = ast_strdupa(notdata);
04437 
04438    AST_STANDARD_APP_ARGS(args, info);  
04439 
04440    if (args.confno) {
04441       ast_copy_string(confno, args.confno, sizeof(confno));
04442       if (ast_strlen_zero(confno)) {
04443          allowretry = 1;
04444       }
04445    }
04446    
04447    if (args.pin)
04448       ast_copy_string(the_pin, args.pin, sizeof(the_pin));
04449 
04450    if (args.options) {
04451       ast_app_parse_options64(meetme_opts, &confflags, optargs, args.options);
04452       dynamic = ast_test_flag64(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
04453       if (ast_test_flag64(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
04454          strcpy(the_pin, "q");
04455 
04456       empty = ast_test_flag64(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
04457       empty_no_pin = ast_test_flag64(&confflags, CONFFLAG_EMPTYNOPIN);
04458       always_prompt = ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
04459    }
04460 
04461    do {
04462       if (retrycnt > 3)
04463          allowretry = 0;
04464       if (empty) {
04465          int i;
04466          struct ast_config *cfg;
04467          struct ast_variable *var;
04468          int confno_int;
04469 
04470          /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
04471          if ((empty_no_pin) || (!dynamic)) {
04472             cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
04473             if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
04474                var = ast_variable_browse(cfg, "rooms");
04475                while (var) {
04476                   char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
04477                   if (!strcasecmp(var->name, "conf")) {
04478                      int found = 0;
04479                      ast_copy_string(parse, var->value, sizeof(parse));
04480                      confno_tmp = strsep(&stringp, "|,");
04481                      if (!dynamic) {
04482                         /* For static:  run through the list and see if this conference is empty */
04483                         AST_LIST_LOCK(&confs);
04484                         AST_LIST_TRAVERSE(&confs, cnf, list) {
04485                            if (!strcmp(confno_tmp, cnf->confno)) {
04486                               /* The conference exists, therefore it's not empty */
04487                               found = 1;
04488                               break;
04489                            }
04490                         }
04491                         AST_LIST_UNLOCK(&confs);
04492                         cnf = NULL;
04493                         if (!found) {
04494                            /* At this point, we have a confno_tmp (static conference) that is empty */
04495                            if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
04496                               /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
04497                                * Case 2:  empty_no_pin and pin is blank (but not NULL)
04498                                * Case 3:  not empty_no_pin
04499                                */
04500                               ast_copy_string(confno, confno_tmp, sizeof(confno));
04501                               break;
04502                            }
04503                         }
04504                      }
04505                   }
04506                   var = var->next;
04507                }
04508                ast_config_destroy(cfg);
04509             }
04510 
04511             if (ast_strlen_zero(confno) && (cfg = ast_load_realtime_multientry("meetme", "confno LIKE", "%", SENTINEL))) {
04512                const char *catg;
04513                for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
04514                   const char *confno_tmp = ast_variable_retrieve(cfg, catg, "confno");
04515                   const char *pin_tmp = ast_variable_retrieve(cfg, catg, "pin");
04516                   if (ast_strlen_zero(confno_tmp)) {
04517                      continue;
04518                   }
04519                   if (!dynamic) {
04520                      int found = 0;
04521                      /* For static:  run through the list and see if this conference is empty */
04522                      AST_LIST_LOCK(&confs);
04523                      AST_LIST_TRAVERSE(&confs, cnf, list) {
04524                         if (!strcmp(confno_tmp, cnf->confno)) {
04525                            /* The conference exists, therefore it's not empty */
04526                            found = 1;
04527                            break;
04528                         }
04529                      }
04530                      AST_LIST_UNLOCK(&confs);
04531                      if (!found) {
04532                         /* At this point, we have a confno_tmp (realtime conference) that is empty */
04533                         if ((empty_no_pin && ast_strlen_zero(pin_tmp)) || (!empty_no_pin)) {
04534                            /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
04535                             * Case 2:  empty_no_pin and pin is blank (but not NULL)
04536                             * Case 3:  not empty_no_pin
04537                             */
04538                            ast_copy_string(confno, confno_tmp, sizeof(confno));
04539                            break;
04540                         }
04541                      }
04542                   }
04543                }
04544                ast_config_destroy(cfg);
04545             }
04546          }
04547 
04548          /* Select first conference number not in use */
04549          if (ast_strlen_zero(confno) && dynamic) {
04550             AST_LIST_LOCK(&confs);
04551             for (i = 0; i < ARRAY_LEN(conf_map); i++) {
04552                if (!conf_map[i]) {
04553                   snprintf(confno, sizeof(confno), "%d", i);
04554                   conf_map[i] = 1;
04555                   break;
04556                }
04557             }
04558             AST_LIST_UNLOCK(&confs);
04559          }
04560 
04561          /* Not found? */
04562          if (ast_strlen_zero(confno)) {
04563             ast_test_suite_event_notify("PLAYBACK", "Message: conf-noempty");
04564             res = ast_streamfile(chan, "conf-noempty", chan->language);
04565             if (!res)
04566                ast_waitstream(chan, "");
04567          } else {
04568             if (sscanf(confno, "%30d", &confno_int) == 1) {
04569                if (!ast_test_flag64(&confflags, CONFFLAG_QUIET)) {
04570                   res = ast_streamfile(chan, "conf-enteringno", chan->language);
04571                   if (!res) {
04572                      ast_waitstream(chan, "");
04573                      res = ast_say_digits(chan, confno_int, "", chan->language);
04574                   }
04575                }
04576             } else {
04577                ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
04578             }
04579          }
04580       }
04581 
04582       while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
04583          /* Prompt user for conference number */
04584          res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
04585          if (res < 0) {
04586             /* Don't try to validate when we catch an error */
04587             confno[0] = '\0';
04588             allowretry = 0;
04589             break;
04590          }
04591       }
04592       if (!ast_strlen_zero(confno)) {
04593          /* Check the validity of the conference */
04594          cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
04595             sizeof(the_pin), 1, &confflags);
04596          if (!cnf) {
04597             int too_early = 0;
04598 
04599             cnf = find_conf_realtime(chan, confno, 1, dynamic, 
04600                the_pin, sizeof(the_pin), 1, &confflags, &too_early, optargs);
04601             if (rt_schedule && too_early)
04602                allowretry = 0;
04603          }
04604 
04605          if (!cnf) {
04606             if (allowretry) {
04607                confno[0] = '\0';
04608                res = ast_streamfile(chan, "conf-invalid", chan->language);
04609                if (!res)
04610                   ast_waitstream(chan, "");
04611                res = -1;
04612             }
04613          } else {
04614             /* Conference requires a pin for specified access level */
04615             int req_pin = !ast_strlen_zero(cnf->pin) ||
04616                (!ast_strlen_zero(cnf->pinadmin) &&
04617                   ast_test_flag64(&confflags, CONFFLAG_ADMIN));
04618             /* The following logic was derived from a
04619              * 4 variable truth table and defines which
04620              * circumstances are not exempt from pin
04621              * checking.
04622              * If this needs to be modified, write the
04623              * truth table back out from the boolean
04624              * expression AB+A'D+C', change the erroneous
04625              * result, and rederive the expression.
04626              * Variables:
04627              *  A: pin provided?
04628              *  B: always prompt?
04629              *  C: dynamic?
04630              *  D: has users? */
04631             int not_exempt = !cnf->isdynamic;
04632             not_exempt = not_exempt || (!ast_strlen_zero(args.pin) && ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT));
04633             not_exempt = not_exempt || (ast_strlen_zero(args.pin) && cnf->users);
04634             if (req_pin && not_exempt) {
04635                char pin[MAX_PIN] = "";
04636                int j;
04637 
04638                /* Allow the pin to be retried up to 3 times */
04639                for (j = 0; j < 3; j++) {
04640                   if (*the_pin && (always_prompt == 0)) {
04641                      ast_copy_string(pin, the_pin, sizeof(pin));
04642                      res = 0;
04643                   } else {
04644                      /* Prompt user for pin if pin is required */
04645                      ast_test_suite_event_notify("PLAYBACK", "Message: conf-getpin\r\n"
04646                         "Channel: %s",
04647                         chan->name);
04648                      res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
04649                   }
04650                   if (res >= 0) {
04651                      if ((!strcasecmp(pin, cnf->pin) &&
04652                           (ast_strlen_zero(cnf->pinadmin) ||
04653                            !ast_test_flag64(&confflags, CONFFLAG_ADMIN))) ||
04654                           (!ast_strlen_zero(cnf->pinadmin) &&
04655                            !strcasecmp(pin, cnf->pinadmin))) {
04656                         /* Pin correct */
04657                         allowretry = 0;
04658                         if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
04659                            if (!ast_strlen_zero(cnf->adminopts)) {
04660                               char *opts = ast_strdupa(cnf->adminopts);
04661                               ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
04662                            }
04663                         } else {
04664                            if (!ast_strlen_zero(cnf->useropts)) {
04665                               char *opts = ast_strdupa(cnf->useropts);
04666                               ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
04667                            }
04668                         }
04669                         /* Run the conference */
04670                         ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
04671                         res = conf_run(chan, cnf, &confflags, optargs);
04672                         break;
04673                      } else {
04674                         /* Pin invalid */
04675                         if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
04676                            res = ast_waitstream(chan, AST_DIGIT_ANY);
04677                            ast_stopstream(chan);
04678                         } else {
04679                            ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
04680                            break;
04681                         }
04682                         if (res < 0)
04683                            break;
04684                         pin[0] = res;
04685                         pin[1] = '\0';
04686                         res = -1;
04687                         if (allowretry)
04688                            confno[0] = '\0';
04689                      }
04690                   } else {
04691                      /* failed when getting the pin */
04692                      res = -1;
04693                      allowretry = 0;
04694                      /* see if we need to get rid of the conference */
04695                      break;
04696                   }
04697 
04698                   /* Don't retry pin with a static pin */
04699                   if (*the_pin && (always_prompt == 0)) {
04700                      break;
04701                   }
04702                }
04703             } else {
04704                /* No pin required */
04705                allowretry = 0;
04706 
04707                /* For RealTime conferences without a pin 
04708                 * should still support loading options
04709                 */
04710                if (!ast_strlen_zero(cnf->useropts)) {
04711                   char *opts = ast_strdupa(cnf->useropts);
04712                   ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
04713                }
04714 
04715                /* Run the conference */
04716                res = conf_run(chan, cnf, &confflags, optargs);
04717             }
04718             dispose_conf(cnf);
04719             cnf = NULL;
04720          }
04721       }
04722    } while (allowretry);
04723 
04724    if (cnf)
04725       dispose_conf(cnf);
04726    
04727    return res;
04728 }

static void conf_flush ( int  fd,
struct ast_channel chan 
) [static]

Definition at line 1894 of file app_meetme.c.

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

Referenced by conf_run().

01895 {
01896    int x;
01897 
01898    /* read any frames that may be waiting on the channel
01899       and throw them away
01900    */
01901    if (chan) {
01902       struct ast_frame *f;
01903 
01904       /* when no frames are available, this will wait
01905          for 1 millisecond maximum
01906       */
01907       while (ast_waitfor(chan, 1) > 0) {
01908          f = ast_read(chan);
01909          if (f)
01910             ast_frfree(f);
01911          else /* channel was hung up or something else happened */
01912             break;
01913       }
01914    }
01915 
01916    /* flush any data sitting in the pseudo channel */
01917    x = DAHDI_FLUSH_ALL;
01918    if (ioctl(fd, DAHDI_FLUSH, &x))
01919       ast_log(LOG_WARNING, "Error flushing channel\n");
01920 
01921 }

static int conf_free ( struct ast_conference conf  )  [static]

Remove the conference from the list and free it.

We assume that this was called while holding conflock.

Definition at line 1926 of file app_meetme.c.

References 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, ast_conference::origframe, ast_conference::playlock, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthreadlock, ast_conference::transframe, ast_conference::transpath, and ast_conference::usercontainer.

Referenced by dispose_conf().

01927 {
01928    int x;
01929    struct announce_listitem *item;
01930    
01931    AST_LIST_REMOVE(&confs, conf, list);
01932    manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01933 
01934    if (conf->recording == MEETME_RECORD_ACTIVE) {
01935       conf->recording = MEETME_RECORD_TERMINATE;
01936       AST_LIST_UNLOCK(&confs);
01937       while (1) {
01938          usleep(1);
01939          AST_LIST_LOCK(&confs);
01940          if (conf->recording == MEETME_RECORD_OFF)
01941             break;
01942          AST_LIST_UNLOCK(&confs);
01943       }
01944    }
01945 
01946    for (x = 0; x < AST_FRAME_BITS; x++) {
01947       if (conf->transframe[x])
01948          ast_frfree(conf->transframe[x]);
01949       if (conf->transpath[x])
01950          ast_translator_free_path(conf->transpath[x]);
01951    }
01952    if (conf->announcethread != AST_PTHREADT_NULL) {
01953       ast_mutex_lock(&conf->announcelistlock);
01954       conf->announcethread_stop = 1;
01955       ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01956       ast_cond_signal(&conf->announcelist_addition);
01957       ast_mutex_unlock(&conf->announcelistlock);
01958       pthread_join(conf->announcethread, NULL);
01959    
01960       while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01961          ast_filedelete(item->namerecloc, NULL);
01962          ao2_ref(item, -1);
01963       }
01964       ast_mutex_destroy(&conf->announcelistlock);
01965    }
01966 
01967    if (conf->origframe)
01968       ast_frfree(conf->origframe);
01969    if (conf->lchan)
01970       ast_hangup(conf->lchan);
01971    if (conf->chan)
01972       ast_hangup(conf->chan);
01973    if (conf->fd >= 0)
01974       close(conf->fd);
01975    if (conf->recordingfilename) {
01976       ast_free(conf->recordingfilename);
01977    }
01978    if (conf->usercontainer) {
01979       ao2_ref(conf->usercontainer, -1);
01980    }
01981    if (conf->recordingformat) {
01982       ast_free(conf->recordingformat);
01983    }
01984    ast_mutex_destroy(&conf->playlock);
01985    ast_mutex_destroy(&conf->listenlock);
01986    ast_mutex_destroy(&conf->recordthreadlock);
01987    ast_mutex_destroy(&conf->announcethreadlock);
01988    ast_free(conf);
01989 
01990    return 0;
01991 }

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

Definition at line 1134 of file app_meetme.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_check_hangup(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_test_suite_event_notify, careful_write(), ast_conference::confno, enter, ENTER, ast_conference::fd, leave, LEAVE, len(), and ast_conference::markedusers.

Referenced by conf_run().

01135 {
01136    unsigned char *data;
01137    int len;
01138    int res = -1;
01139 
01140    ast_test_suite_event_notify("CONFPLAY", "Channel: %s\r\n"
01141                            "Conference: %s\r\n"
01142                            "Marked: %d",
01143                            chan->name,
01144                            conf->confno,
01145                            conf->markedusers);
01146 
01147    if (!ast_check_hangup(chan))
01148       res = ast_autoservice_start(chan);
01149 
01150    AST_LIST_LOCK(&confs);
01151 
01152    switch(sound) {
01153    case ENTER:
01154       data = enter;
01155       len = sizeof(enter);
01156       break;
01157    case LEAVE:
01158       data = leave;
01159       len = sizeof(leave);
01160       break;
01161    default:
01162       data = NULL;
01163       len = 0;
01164    }
01165    if (data) {
01166       careful_write(conf->fd, data, len, 1);
01167    }
01168 
01169    AST_LIST_UNLOCK(&confs);
01170 
01171    if (!res) 
01172       ast_autoservice_stop(chan);
01173 }

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

Definition at line 1993 of file app_meetme.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_log(), ast_write(), ast_conf_user::chan, LOG_WARNING, and ast_conference::usercontainer.

Referenced by conf_run().

01995 {
01996    struct ast_conf_user *user;
01997    struct ao2_iterator user_iter;
01998 
01999    user_iter = ao2_iterator_init(conf->usercontainer, 0);
02000    while ((user = ao2_iterator_next(&user_iter))) {
02001       if (user == sender) {
02002          ao2_ref(user, -1);
02003          continue;
02004       }
02005       if (ast_write(user->chan, f) < 0)
02006          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
02007       ao2_ref(user, -1);
02008    }
02009    ao2_iterator_destroy(&user_iter);
02010 }

static int conf_run ( struct ast_channel chan,
struct ast_conference conf,
struct ast_flags64 confflags,
char *  optargs[] 
) [static]

Definition at line 2754 of file app_meetme.c.

References volume::actual, ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, announce_thread(), ao2_alloc, ao2_callback, ao2_link, ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_cond_signal, ast_config_AST_SPOOL_DIR, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), AST_DEVSTATE_NOT_CACHABLE, AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_silence(), ast_exists_extension(), ast_filedelete(), AST_FORMAT_SLINEAR, ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_free, ast_frfree, AST_FRIENDLY_OFFSET, ast_func_write(), ast_goto_if_exists(), ast_hangup(), ast_indicate(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), ast_manager_event, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), ast_mktime(), ast_module_helper(), ast_moh_stop(), ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_read(), ast_read_noaudio(), ast_realtime_require_field(), ast_record_review(), ast_request(), ast_safe_sleep(), ast_samp2tv(), ast_say_digits(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_test_flag64, ast_test_suite_event_notify, ast_translate(), ast_translator_build_path(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_update_realtime(), ast_variables_destroy(), ast_verb, ast_verbose, ast_waitfor_nandfds(), ast_waitstream(), ast_write(), ast_channel::audiohooks, ast_conference::bookid, ast_channel::caller, can_write(), careful_write(), ast_conference::chan, ast_conf_user::chan, ast_frame_subclass::codec, conf_flush(), CONF_HASJOIN, CONF_HASLEFT, conf_play(), conf_queue_dtmf(), CONF_SIZE, conf_start_moh(), CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_DONT_DENOISE, CONFFLAG_DURATION_LIMIT, CONFFLAG_DURATION_STOP, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROMSG, 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, ast_channel::connected, ast_channel::context, ast_conf_user::dahdichannel, ast_conference::dahdiconf, ast_frame::data, ast_frame::datalen, DATE_FORMAT, volume::desired, dtmfstr, ast_conf_user::end_sound, ast_conference::endalert, ast_conference::endtime, ENTER, errno, EVENT_FLAG_CALL, exitcontext, f, ast_conference::fd, ast_channel::fds, ast_frame::frametype, ast_conference::gmuted, ast_party_connected_line::id, ast_party_caller::id, ast_frame_subclass::integer, ast_conference::isdynamic, ast_conf_user::jointime, ast_conf_user::kicktime, ast_conference::lchan, LEAVE, ast_conf_user::listen, ast_conference::listenlock, ast_conference::locked, LOG_WARNING, ast_channel::macrocontext, ast_conference::markedusers, ast_conference::maxusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, meetme_menu(), MENU_ADMIN, MENU_DISABLED, MENU_NORMAL, ast_channel::monitor, ast_variable::name, ast_party_id::name, ast_conf_user::namerecloc, ast_variable::next, ast_party_id::number, OBJ_NODATA, ast_frame::offset, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_EXITKEYS, OPT_ARG_INTROMSG, OPT_ARG_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_COR, ast_frame::samples, set_talk_volume(), set_user_talking(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_conf_user::start_time, ast_party_name::str, ast_party_number::str, ast_frame::subclass, ast_conf_user::talk, ast_conf_user::talking, ast_channel::tech, THRESHOLD_SILENCE, ast_conf_user::timelimit, ast_conference::transframe, ast_conference::transpath, ast_channel_tech::type, ast_conference::uniqueid, user_max_cmp(), ast_conf_user::user_no, ast_conference::usercontainer, ast_conf_user::userflags, ast_conference::users, ast_party_name::valid, ast_party_number::valid, ast_variable::value, var, 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().

02755 {
02756    struct ast_conf_user *user = NULL;
02757    int fd;
02758    struct dahdi_confinfo dahdic, dahdic_empty;
02759    struct ast_frame *f;
02760    struct ast_channel *c;
02761    struct ast_frame fr;
02762    int outfd;
02763    int ms;
02764    int nfds;
02765    int res;
02766    int retrydahdi;
02767    int origfd;
02768    int musiconhold = 0, mohtempstopped = 0;
02769    int firstpass = 0;
02770    int lastmarked = 0;
02771    int currentmarked = 0;
02772    int ret = -1;
02773    int x;
02774    enum menu_modes menu_mode = MENU_DISABLED;
02775    int talkreq_manager = 0;
02776    int using_pseudo = 0;
02777    int duration = 20;
02778    int sent_event = 0;
02779    int checked = 0;
02780    int announcement_played = 0;
02781    struct timeval now;
02782    struct ast_dsp *dsp = NULL;
02783    struct ast_app *agi_app;
02784    char *agifile, *mod_speex;
02785    const char *agifiledefault = "conf-background.agi", *tmpvar;
02786    char meetmesecs[30] = "";
02787    char exitcontext[AST_MAX_CONTEXT] = "";
02788    char recordingtmp[AST_MAX_EXTENSION] = "";
02789    char members[10] = "";
02790    int dtmf = 0, opt_waitmarked_timeout = 0;
02791    time_t timeout = 0;
02792    struct dahdi_bufferinfo bi;
02793    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
02794    char *buf = __buf + AST_FRIENDLY_OFFSET;
02795    char *exitkeys = NULL;
02796    unsigned int calldurationlimit = 0;
02797    long timelimit = 0;
02798    long play_warning = 0;
02799    long warning_freq = 0;
02800    const char *warning_sound = NULL;
02801    const char *end_sound = NULL;
02802    char *parse;   
02803    long time_left_ms = 0;
02804    struct timeval nexteventts = { 0, };
02805    int to;
02806    int setusercount = 0;
02807    int confsilence = 0, totalsilence = 0;
02808 
02809    if (!(user = ao2_alloc(sizeof(*user), NULL))) {
02810       return ret;
02811    }
02812 
02813    /* Possible timeout waiting for marked user */
02814    if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
02815       !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
02816       (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
02817       (opt_waitmarked_timeout > 0)) {
02818       timeout = time(NULL) + opt_waitmarked_timeout;
02819    }
02820       
02821    if (ast_test_flag64(confflags, CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
02822       calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
02823       ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
02824    }
02825    
02826    if (ast_test_flag64(confflags, CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
02827       char *limit_str, *warning_str, *warnfreq_str;
02828       const char *var;
02829  
02830       parse = optargs[OPT_ARG_DURATION_LIMIT];
02831       limit_str = strsep(&parse, ":");
02832       warning_str = strsep(&parse, ":");
02833       warnfreq_str = parse;
02834  
02835       timelimit = atol(limit_str);
02836       if (warning_str)
02837          play_warning = atol(warning_str);
02838       if (warnfreq_str)
02839          warning_freq = atol(warnfreq_str);
02840  
02841       if (!timelimit) {
02842          timelimit = play_warning = warning_freq = 0;
02843          warning_sound = NULL;
02844       } else if (play_warning > timelimit) {       
02845          if (!warning_freq) {
02846             play_warning = 0;
02847          } else {
02848             while (play_warning > timelimit)
02849                play_warning -= warning_freq;
02850             if (play_warning < 1)
02851                play_warning = warning_freq = 0;
02852          }
02853       }
02854 
02855       ast_verb(3, "Setting conference duration limit to: %ldms.\n", timelimit);
02856       if (play_warning) {
02857          ast_verb(3, "Setting warning time to %ldms from the conference duration limit.\n", play_warning);
02858       }
02859       if (warning_freq) {
02860          ast_verb(3, "Setting warning frequency to %ldms.\n", warning_freq);
02861       }
02862 
02863       ast_channel_lock(chan);
02864       if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
02865          var = ast_strdupa(var);
02866       }
02867       ast_channel_unlock(chan);
02868 
02869       warning_sound = var ? var : "timeleft";
02870       
02871       ast_channel_lock(chan);
02872       if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
02873          var = ast_strdupa(var);
02874       }
02875       ast_channel_unlock(chan);
02876       
02877       end_sound = var ? var : NULL;
02878          
02879       /* undo effect of S(x) in case they are both used */
02880       calldurationlimit = 0;
02881       /* more efficient do it like S(x) does since no advanced opts */
02882       if (!play_warning && !end_sound && timelimit) { 
02883          calldurationlimit = timelimit / 1000;
02884          timelimit = play_warning = warning_freq = 0;
02885       } else {
02886          ast_debug(2, "Limit Data for this call:\n");
02887          ast_debug(2, "- timelimit     = %ld\n", timelimit);
02888          ast_debug(2, "- play_warning  = %ld\n", play_warning);
02889          ast_debug(2, "- warning_freq  = %ld\n", warning_freq);
02890          ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
02891          ast_debug(2, "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
02892       }
02893    }
02894 
02895    /* Get exit keys */
02896    if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
02897       if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
02898          exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
02899       else
02900          exitkeys = ast_strdupa("#"); /* Default */
02901    }
02902    
02903    if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
02904       if (!conf->recordingfilename) {
02905          const char *var;
02906          ast_channel_lock(chan);
02907          if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
02908             conf->recordingfilename = ast_strdup(var);
02909          }
02910          if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
02911             conf->recordingformat = ast_strdup(var);
02912          }
02913          ast_channel_unlock(chan);
02914          if (!conf->recordingfilename) {
02915             snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
02916             conf->recordingfilename = ast_strdup(recordingtmp);
02917          }
02918          if (!conf->recordingformat) {
02919             conf->recordingformat = ast_strdup("wav");
02920          }
02921          ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
02922                 conf->confno, conf->recordingfilename, conf->recordingformat);
02923       }
02924    }
02925 
02926    ast_mutex_lock(&conf->recordthreadlock);
02927    if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
02928       ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, chan, "pseudo", NULL)))) {
02929       ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
02930       ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
02931       dahdic.chan = 0;
02932       dahdic.confno = conf->dahdiconf;
02933       dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
02934       if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
02935          ast_log(LOG_WARNING, "Error starting listen channel\n");
02936          ast_hangup(conf->lchan);
02937          conf->lchan = NULL;
02938       } else {
02939          ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
02940       }
02941    }
02942    ast_mutex_unlock(&conf->recordthreadlock);
02943 
02944    ast_mutex_lock(&conf->announcethreadlock);
02945    if ((conf->announcethread == AST_PTHREADT_NULL) && !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
02946       (ast_test_flag64(confflags, CONFFLAG_INTROUSER) || ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW))) {
02947       ast_mutex_init(&conf->announcelistlock);
02948       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
02949       ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
02950    }
02951    ast_mutex_unlock(&conf->announcethreadlock);
02952 
02953    time(&user->jointime);
02954    
02955    user->timelimit = timelimit;
02956    user->play_warning = play_warning;
02957    user->warning_freq = warning_freq;
02958    user->warning_sound = warning_sound;
02959    user->end_sound = end_sound;  
02960    
02961    if (calldurationlimit > 0) {
02962       time(&user->kicktime);
02963       user->kicktime = user->kicktime + calldurationlimit;
02964    }
02965    
02966    if (ast_tvzero(user->start_time))
02967       user->start_time = ast_tvnow();
02968    time_left_ms = user->timelimit;
02969    
02970    if (user->timelimit) {
02971       nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
02972       nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
02973    }
02974 
02975    if (conf->locked && (!ast_test_flag64(confflags, CONFFLAG_ADMIN))) {
02976       /* Sorry, but this conference is locked! */  
02977       if (!ast_streamfile(chan, "conf-locked", chan->language))
02978          ast_waitstream(chan, "");
02979       goto outrun;
02980    }
02981 
02982       ast_mutex_lock(&conf->playlock);
02983 
02984    if (rt_schedule && conf->maxusers) {
02985       if (conf->users >= conf->maxusers) {
02986          /* Sorry, but this confernce has reached the participant limit! */   
02987          if (!ast_streamfile(chan, "conf-full", chan->language))
02988             ast_waitstream(chan, "");
02989          ast_mutex_unlock(&conf->playlock);
02990          goto outrun;
02991       }
02992    }
02993 
02994    ao2_lock(conf->usercontainer);
02995    ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &user->user_no);
02996    user->user_no++;
02997    ao2_link(conf->usercontainer, user);
02998    ao2_unlock(conf->usercontainer);
02999 
03000    user->chan = chan;
03001    user->userflags = *confflags;
03002    user->adminflags = ast_test_flag64(confflags, CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
03003    user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
03004    user->talking = -1;
03005 
03006    ast_mutex_unlock(&conf->playlock);
03007 
03008    if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
03009       ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW))) {
03010       char destdir[PATH_MAX];
03011 
03012       snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
03013 
03014       if (ast_mkdir(destdir, 0777) != 0) {
03015          ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
03016          goto outrun;
03017       }
03018 
03019       snprintf(user->namerecloc, sizeof(user->namerecloc),
03020           "%s/meetme-username-%s-%d", destdir,
03021           conf->confno, user->user_no);
03022       if (ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW))
03023          res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
03024       else
03025          res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
03026       if (res == -1)
03027          goto outrun;
03028    }
03029 
03030    ast_mutex_lock(&conf->playlock);
03031 
03032    if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER))
03033       conf->markedusers++;
03034    conf->users++;
03035    if (rt_log_members) {
03036       /* Update table */
03037       snprintf(members, sizeof(members), "%d", conf->users);
03038       ast_realtime_require_field("meetme",
03039          "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
03040          "members", RQ_UINTEGER1, strlen(members),
03041          NULL);
03042       ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
03043    }
03044    setusercount = 1;
03045 
03046    /* This device changed state now - if this is the first user */
03047    if (conf->users == 1)
03048       ast_devstate_changed(AST_DEVICE_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
03049 
03050    ast_mutex_unlock(&conf->playlock);
03051 
03052    /* return the unique ID of the conference */
03053    pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
03054 
03055    if (ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT)) {
03056       ast_channel_lock(chan);
03057       if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
03058          ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
03059       } else if (!ast_strlen_zero(chan->macrocontext)) {
03060          ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
03061       } else {
03062          ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
03063       }
03064       ast_channel_unlock(chan);
03065    }
03066 
03067    /* Play an arbitrary intro message */
03068    if (ast_test_flag64(confflags, CONFFLAG_INTROMSG) &&
03069          !ast_strlen_zero(optargs[OPT_ARG_INTROMSG])) {
03070       if (!ast_streamfile(chan, optargs[OPT_ARG_INTROMSG], chan->language)) {
03071          ast_waitstream(chan, "");
03072       }
03073    }
03074 
03075    if (!ast_test_flag64(confflags, (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
03076       if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED))
03077          if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
03078             ast_waitstream(chan, "");
03079       if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && conf->markedusers == 0)
03080          if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
03081             ast_waitstream(chan, "");
03082    }
03083 
03084    if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_ANNOUNCEUSERCOUNT) &&
03085       conf->users > 1) {
03086       int keepplaying = 1;
03087 
03088       if (conf->users == 2) { 
03089          if (!ast_streamfile(chan, "conf-onlyone", chan->language)) {
03090             res = ast_waitstream(chan, AST_DIGIT_ANY);
03091             ast_stopstream(chan);
03092             if (res > 0)
03093                keepplaying = 0;
03094             else if (res == -1)
03095                goto outrun;
03096          }
03097       } else { 
03098          if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
03099             res = ast_waitstream(chan, AST_DIGIT_ANY);
03100             ast_stopstream(chan);
03101             if (res > 0)
03102                keepplaying = 0;
03103             else if (res == -1)
03104                goto outrun;
03105          }
03106          if (keepplaying) {
03107             res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
03108             if (res > 0)
03109                keepplaying = 0;
03110             else if (res == -1)
03111                goto outrun;
03112          }
03113          if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
03114             res = ast_waitstream(chan, AST_DIGIT_ANY);
03115             ast_stopstream(chan);
03116             if (res > 0)
03117                keepplaying = 0;
03118             else if (res == -1) 
03119                goto outrun;
03120          }
03121       }
03122    }
03123 
03124    if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
03125       /* We're leaving this alone until the state gets changed to up */
03126       ast_indicate(chan, -1);
03127    }
03128 
03129    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
03130       ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
03131       goto outrun;
03132    }
03133 
03134    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
03135       ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
03136       goto outrun;
03137    }
03138 
03139    /* Reduce background noise from each participant */
03140    if (!ast_test_flag64(confflags, CONFFLAG_DONT_DENOISE) &&
03141       (mod_speex = ast_module_helper("", "func_speex", 0, 0, 0, 0))) {
03142       ast_free(mod_speex);
03143       ast_func_write(chan, "DENOISE(rx)", "on");
03144    }
03145 
03146    retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
03147    user->dahdichannel = !retrydahdi;
03148 
03149  dahdiretry:
03150    origfd = chan->fds[0];
03151    if (retrydahdi) {
03152       /* open pseudo in non-blocking mode */
03153       fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
03154       if (fd < 0) {
03155          ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
03156          goto outrun;
03157       }
03158       using_pseudo = 1;
03159       /* Setup buffering information */
03160       memset(&bi, 0, sizeof(bi));
03161       bi.bufsize = CONF_SIZE / 2;
03162       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
03163       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
03164       bi.numbufs = audio_buffers;
03165       if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
03166          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
03167          close(fd);
03168          goto outrun;
03169       }
03170       x = 1;
03171       if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
03172          ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
03173          close(fd);
03174          goto outrun;
03175       }
03176       nfds = 1;
03177    } else {
03178       /* XXX Make sure we're not running on a pseudo channel XXX */
03179       fd = chan->fds[0];
03180       nfds = 0;
03181    }
03182    memset(&dahdic, 0, sizeof(dahdic));
03183    memset(&dahdic_empty, 0, sizeof(dahdic_empty));
03184    /* Check to see if we're in a conference... */
03185    dahdic.chan = 0;  
03186    if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
03187       ast_log(LOG_WARNING, "Error getting conference\n");
03188       close(fd);
03189       goto outrun;
03190    }
03191    if (dahdic.confmode) {
03192       /* Whoa, already in a conference...  Retry... */
03193       if (!retrydahdi) {
03194          ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
03195          retrydahdi = 1;
03196          goto dahdiretry;
03197       }
03198    }
03199    memset(&dahdic, 0, sizeof(dahdic));
03200    /* Add us to the conference */
03201    dahdic.chan = 0;  
03202    dahdic.confno = conf->dahdiconf;
03203 
03204    if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
03205       ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
03206       struct announce_listitem *item;
03207       if (!(item = ao2_alloc(sizeof(*item), NULL)))
03208          goto outrun;
03209       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
03210       ast_copy_string(item->language, chan->language, sizeof(item->language));
03211       item->confchan = conf->chan;
03212       item->confusers = conf->users;
03213       item->announcetype = CONF_HASJOIN;
03214       ast_mutex_lock(&conf->announcelistlock);
03215       ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
03216       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
03217       ast_cond_signal(&conf->announcelist_addition);
03218       ast_mutex_unlock(&conf->announcelistlock);
03219 
03220       while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
03221          ;
03222       }
03223       ao2_ref(item, -1);
03224    }
03225 
03226    if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && !conf->markedusers)
03227       dahdic.confmode = DAHDI_CONF_CONF;
03228    else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
03229       dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
03230    else if (ast_test_flag64(confflags, CONFFLAG_TALKER))
03231       dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
03232    else 
03233       dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
03234 
03235    if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03236       ast_log(LOG_WARNING, "Error setting conference\n");
03237       close(fd);
03238       goto outrun;
03239    }
03240    ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf);
03241 
03242    if (!sent_event) {
03243       ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeJoin",
03244          "Channel: %s\r\n"
03245          "Uniqueid: %s\r\n"
03246          "Meetme: %s\r\n"
03247          "Usernum: %d\r\n"
03248          "CallerIDnum: %s\r\n"
03249          "CallerIDname: %s\r\n"
03250          "ConnectedLineNum: %s\r\n"
03251          "ConnectedLineName: %s\r\n",
03252          chan->name, chan->uniqueid, conf->confno,
03253          user->user_no,
03254          S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
03255          S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>"),
03256          S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
03257          S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<unknown>")
03258          );
03259       sent_event = 1;
03260    }
03261 
03262    if (!firstpass && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
03263       !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
03264       firstpass = 1;
03265       if (!ast_test_flag64(confflags, CONFFLAG_QUIET))
03266          if (!ast_test_flag64(confflags, CONFFLAG_WAITMARKED) || (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
03267             (conf->markedusers >= 1))) {
03268             conf_play(chan, conf, ENTER);
03269          }
03270    }
03271 
03272    conf_flush(fd, chan);
03273 
03274    if (dsp)
03275       ast_dsp_free(dsp);
03276 
03277    if (!(dsp = ast_dsp_new())) {
03278       ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
03279       res = -1;
03280    }
03281 
03282    if (ast_test_flag64(confflags, CONFFLAG_AGI)) {
03283       /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
03284          or use default filename of conf-background.agi */
03285 
03286       ast_channel_lock(chan);
03287       if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
03288          agifile = ast_strdupa(tmpvar);
03289       } else {
03290          agifile = ast_strdupa(agifiledefault);
03291       }
03292       ast_channel_unlock(chan);
03293       
03294       if (user->dahdichannel) {
03295          /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
03296          x = 1;
03297          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
03298       }
03299       /* Find a pointer to the agi app and execute the script */
03300       agi_app = pbx_findapp("agi");
03301       if (agi_app) {
03302          ret = pbx_exec(chan, agi_app, agifile);
03303       } else {
03304          ast_log(LOG_WARNING, "Could not find application (agi)\n");
03305          ret = -2;
03306       }
03307       if (user->dahdichannel) {
03308          /*  Remove CONFMUTE mode on DAHDI channel */
03309          x = 0;
03310          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
03311       }
03312    } else {
03313       int lastusers = conf->users;
03314       if (user->dahdichannel && ast_test_flag64(confflags, CONFFLAG_STARMENU)) {
03315          /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
03316          x = 1;
03317          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
03318       }
03319 
03320       for (;;) {
03321          int menu_was_active = 0;
03322 
03323          outfd = -1;
03324          ms = -1;
03325          now = ast_tvnow();
03326 
03327          if (rt_schedule && conf->endtime) {
03328             char currenttime[32];
03329             long localendtime = 0;
03330             int extended = 0;
03331             struct ast_tm tm;
03332             struct ast_variable *var, *origvar;
03333             struct timeval tmp;
03334 
03335             if (now.tv_sec % 60 == 0) {
03336                if (!checked) {
03337                   ast_localtime(&now, &tm, NULL);
03338                   ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03339                   var = origvar = ast_load_realtime("meetme", "confno",
03340                      conf->confno, "starttime <=", currenttime,
03341                       "endtime >=", currenttime, NULL);
03342 
03343                   for ( ; var; var = var->next) {
03344                      if (!strcasecmp(var->name, "endtime")) {
03345                         struct ast_tm endtime_tm;
03346                         ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
03347                         tmp = ast_mktime(&endtime_tm, NULL);
03348                         localendtime = tmp.tv_sec;
03349                      }
03350                   }
03351                   ast_variables_destroy(origvar);
03352 
03353                   /* A conference can be extended from the
03354                      Admin/User menu or by an external source */
03355                   if (localendtime > conf->endtime){
03356                      conf->endtime = localendtime;
03357                      extended = 1;
03358                   }
03359 
03360                   if (conf->endtime && (now.tv_sec >= conf->endtime)) {
03361                      ast_verbose("Quitting time...\n");
03362                      goto outrun;
03363                   }
03364 
03365                   if (!announcement_played && conf->endalert) {
03366                      if (now.tv_sec + conf->endalert >= conf->endtime) {
03367                         if (!ast_streamfile(chan, "conf-will-end-in", chan->language))
03368                            ast_waitstream(chan, "");
03369                         ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language);
03370                         if (!ast_streamfile(chan, "minutes", chan->language))
03371                            ast_waitstream(chan, "");
03372                         if (musiconhold) {
03373                            conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03374                         }
03375                         announcement_played = 1;
03376                      }
03377                   }
03378 
03379                   if (extended) {
03380                      announcement_played = 0;
03381                   }
03382 
03383                   checked = 1;
03384                }
03385             } else {
03386                checked = 0;
03387             }
03388          }
03389 
03390          if (user->kicktime && (user->kicktime <= now.tv_sec)) {
03391             if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
03392                ret = 0;
03393             } else {
03394                ret = -1;
03395             }
03396             break;
03397          }
03398   
03399          to = -1;
03400          if (user->timelimit) {
03401             int minutes = 0, seconds = 0, remain = 0;
03402  
03403             to = ast_tvdiff_ms(nexteventts, now);
03404             if (to < 0) {
03405                to = 0;
03406             }
03407             time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
03408             if (time_left_ms < to) {
03409                to = time_left_ms;
03410             }
03411    
03412             if (time_left_ms <= 0) {
03413                if (user->end_sound) {                 
03414                   res = ast_streamfile(chan, user->end_sound, chan->language);
03415                   res = ast_waitstream(chan, "");
03416                }
03417                if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
03418                   ret = 0;
03419                } else {
03420                   ret = -1;
03421                }
03422                break;
03423             }
03424             
03425             if (!to) {
03426                if (time_left_ms >= 5000) {                  
03427                   
03428                   remain = (time_left_ms + 500) / 1000;
03429                   if (remain / 60 >= 1) {
03430                      minutes = remain / 60;
03431                      seconds = remain % 60;
03432                   } else {
03433                      seconds = remain;
03434                   }
03435                   
03436                   /* force the time left to round up if appropriate */
03437                   if (user->warning_sound && user->play_warning) {
03438                      if (!strcmp(user->warning_sound, "timeleft")) {
03439                         
03440                         res = ast_streamfile(chan, "vm-youhave", chan->language);
03441                         res = ast_waitstream(chan, "");
03442                         if (minutes) {
03443                            res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL);
03444                            res = ast_streamfile(chan, "queue-minutes", chan->language);
03445                            res = ast_waitstream(chan, "");
03446                         }
03447                         if (seconds) {
03448                            res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL);
03449                            res = ast_streamfile(chan, "queue-seconds", chan->language);
03450                            res = ast_waitstream(chan, "");
03451                         }
03452                      } else {
03453                         res = ast_streamfile(chan, user->warning_sound, chan->language);
03454                         res = ast_waitstream(chan, "");
03455                      }
03456                      if (musiconhold) {
03457                         conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03458                      }
03459                   }
03460                }
03461                if (user->warning_freq) {
03462                   nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
03463                } else {
03464                   nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
03465                }
03466             }
03467          }
03468 
03469          now = ast_tvnow();
03470          if (timeout && now.tv_sec >= timeout) {
03471             if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
03472                ret = 0;
03473             } else {
03474                ret = -1;
03475             }
03476             break;
03477          }
03478 
03479          /* if we have just exited from the menu, and the user had a channel-driver
03480             volume adjustment, restore it
03481          */
03482          if (!menu_mode && menu_was_active && user->listen.desired && !user->listen.actual) {
03483             set_talk_volume(user, user->listen.desired);
03484          }
03485 
03486          menu_was_active = menu_mode;
03487 
03488          currentmarked = conf->markedusers;
03489          if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
03490              ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
03491              ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
03492              lastmarked == 0) {
03493             if (currentmarked == 1 && conf->users > 1) {
03494                ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
03495                if (conf->users - 1 == 1) {
03496                   if (!ast_streamfile(chan, "conf-userwilljoin", chan->language)) {
03497                      ast_waitstream(chan, "");
03498                   }
03499                } else {
03500                   if (!ast_streamfile(chan, "conf-userswilljoin", chan->language)) {
03501                      ast_waitstream(chan, "");
03502                   }
03503                }
03504             }
03505             if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
03506                if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) {
03507                   ast_waitstream(chan, "");
03508                }
03509             }
03510          }
03511 
03512          /* Update the struct with the actual confflags */
03513          user->userflags = *confflags;
03514 
03515          if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
03516             if (currentmarked == 0) {
03517                if (lastmarked != 0) {
03518                   if (!ast_test_flag64(confflags, CONFFLAG_QUIET)) {
03519                      if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language)) {
03520                         ast_waitstream(chan, "");
03521                      }
03522                   }
03523                   if (ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
03524                      if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
03525                         ret = 0;
03526                      }
03527                      break;
03528                   } else {
03529                      dahdic.confmode = DAHDI_CONF_CONF;
03530                      if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03531                         ast_log(LOG_WARNING, "Error setting conference\n");
03532                         close(fd);
03533                         goto outrun;
03534                      }
03535                   }
03536                }
03537                if (!musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
03538                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03539                   musiconhold = 1;
03540                }
03541             } else if (currentmarked >= 1 && lastmarked == 0) {
03542                /* Marked user entered, so cancel timeout */
03543                timeout = 0;
03544                if (ast_test_flag64(confflags, CONFFLAG_MONITOR)) {
03545                   dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
03546                } else if (ast_test_flag64(confflags, CONFFLAG_TALKER)) {
03547                   dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
03548                } else {
03549                   dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
03550                }
03551                if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03552                   ast_log(LOG_WARNING, "Error setting conference\n");
03553                   close(fd);
03554                   goto outrun;
03555                }
03556                if (musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
03557                   ast_moh_stop(chan);
03558                   musiconhold = 0;
03559                }
03560                if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && 
03561                   !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
03562                   if (!ast_streamfile(chan, "conf-placeintoconf", chan->language)) {
03563                      ast_waitstream(chan, "");
03564                   }
03565                   conf_play(chan, conf, ENTER);
03566                }
03567             }
03568          }
03569 
03570          /* trying to add moh for single person conf */
03571          if (ast_test_flag64(confflags, CONFFLAG_MOH) && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
03572             if (conf->users == 1) {
03573                if (!musiconhold) {
03574                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03575                   musiconhold = 1;
03576                } 
03577             } else {
03578                if (musiconhold) {
03579                   ast_moh_stop(chan);
03580                   musiconhold = 0;
03581                }
03582             }
03583          }
03584          
03585          /* Leave if the last marked user left */
03586          if (currentmarked == 0 && lastmarked != 0 && ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
03587             if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
03588                ret = 0;
03589             } else {
03590                ret = -1;
03591             }
03592             break;
03593          }
03594 
03595          /* Throw a TestEvent if a user exit did not cause this user to leave the conference */
03596          if (conf->users != lastusers) {
03597             if (conf->users < lastusers) {
03598                ast_test_suite_event_notify("NOEXIT", "Message: CONFFLAG_MARKEDEXIT\r\nLastUsers: %d\r\nUsers: %d", lastusers, conf->users);
03599             }
03600             lastusers = conf->users;
03601          }
03602 
03603          /* Check if my modes have changed */
03604 
03605          /* If I should be muted but am still talker, mute me */
03606          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
03607             dahdic.confmode ^= DAHDI_CONF_TALKER;
03608             if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03609                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
03610                ret = -1;
03611                break;
03612             }
03613 
03614             /* Indicate user is not talking anymore - change him to unmonitored state */
03615             if (ast_test_flag64(confflags,  (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) {
03616                set_user_talking(chan, conf, user, -1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
03617             }
03618 
03619             ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute",
03620                "Channel: %s\r\n"
03621                "Uniqueid: %s\r\n"
03622                "Meetme: %s\r\n"
03623                "Usernum: %d\r\n"
03624                "Status: on\r\n",
03625                chan->name, chan->uniqueid, conf->confno, user->user_no);
03626          }
03627 
03628          /* If I should be un-muted but am not talker, un-mute me */
03629          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
03630             dahdic.confmode |= DAHDI_CONF_TALKER;
03631             if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03632                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
03633                ret = -1;
03634                break;
03635             }
03636 
03637             ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute",
03638                "Channel: %s\r\n"
03639                "Uniqueid: %s\r\n"
03640                "Meetme: %s\r\n"
03641                "Usernum: %d\r\n"
03642                "Status: off\r\n",
03643                chan->name, chan->uniqueid, conf->confno, user->user_no);
03644          }
03645          
03646          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
03647             (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
03648             talkreq_manager = 1;
03649 
03650             ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest",
03651                "Channel: %s\r\n"
03652                "Uniqueid: %s\r\n"
03653                "Meetme: %s\r\n"
03654                "Usernum: %d\r\n"
03655                "Status: on\r\n",
03656                chan->name, chan->uniqueid, conf->confno, user->user_no);
03657          }
03658 
03659          
03660          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
03661             !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
03662             talkreq_manager = 0;
03663             ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest",
03664                "Channel: %s\r\n"
03665                "Uniqueid: %s\r\n"
03666                "Meetme: %s\r\n"
03667                "Usernum: %d\r\n"
03668                "Status: off\r\n",
03669                chan->name, chan->uniqueid, conf->confno, user->user_no);
03670          }
03671          
03672          /* If I have been kicked, exit the conference */
03673          if (user->adminflags & ADMINFLAG_KICKME) {
03674             /* You have been kicked. */
03675             if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && 
03676                !ast_streamfile(chan, "conf-kicked", chan->language)) {
03677                ast_waitstream(chan, "");
03678             }
03679             ret = 0;
03680             break;
03681          }
03682 
03683          /* Perform a hangup check here since ast_waitfor_nandfds will not always be able to get a channel after a hangup has occurred */
03684          if (ast_check_hangup(chan)) {
03685             break;
03686          }
03687 
03688          c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
03689 
03690          if (c) {
03691             char dtmfstr[2] = "";
03692 
03693             if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) {
03694                if (using_pseudo) {
03695                   /* Kill old pseudo */
03696                   close(fd);
03697                   using_pseudo = 0;
03698                }
03699                ast_debug(1, "Ooh, something swapped out under us, starting over\n");
03700                retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0);
03701                user->dahdichannel = !retrydahdi;
03702                goto dahdiretry;
03703             }
03704             if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
03705                f = ast_read_noaudio(c);
03706             } else {
03707                f = ast_read(c);
03708             }
03709             if (!f) {
03710                break;
03711             }
03712             if (f->frametype == AST_FRAME_DTMF) {
03713                dtmfstr[0] = f->subclass.integer;
03714                dtmfstr[1] = '\0';
03715             }
03716 
03717             if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.codec == AST_FORMAT_SLINEAR)) {
03718                if (user->talk.actual) {
03719                   ast_frame_adjust_volume(f, user->talk.actual);
03720                }
03721 
03722                if (ast_test_flag64(confflags, (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER))) {
03723                   if (user->talking == -1) {
03724                      user->talking = 0;
03725                   }
03726 
03727                   res = ast_dsp_silence(dsp, f, &totalsilence);
03728                   if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
03729                      set_user_talking(chan, conf, user, 1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
03730                   }
03731 
03732                   if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
03733                      set_user_talking(chan, conf, user, 0, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
03734                   }
03735                }
03736                if (using_pseudo) {
03737                   /* Absolutely do _not_ use careful_write here...
03738                      it is important that we read data from the channel
03739                      as fast as it arrives, and feed it into the conference.
03740                      The buffering in the pseudo channel will take care of any
03741                      timing differences, unless they are so drastic as to lose
03742                      audio frames (in which case carefully writing would only
03743                      have delayed the audio even further).
03744                   */
03745                   /* As it turns out, we do want to use careful write.  We just
03746                      don't want to block, but we do want to at least *try*
03747                      to write out all the samples.
03748                    */
03749                   if (user->talking || !ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER)) {
03750                      careful_write(fd, f->data.ptr, f->datalen, 0);
03751                   }
03752                }
03753             } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '*') && ast_test_flag64(confflags, CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_mode)) {
03754                if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
03755                   conf_queue_dtmf(conf, user, f);
03756                }
03757                if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
03758                   ast_log(LOG_WARNING, "Error setting conference\n");
03759                   close(fd);
03760                   ast_frfree(f);
03761                   goto outrun;
03762                }
03763 
03764                /* if we are entering the menu, and the user has a channel-driver
03765                   volume adjustment, clear it
03766                */
03767                if (!menu_mode && user->talk.desired && !user->talk.actual) {
03768                   set_talk_volume(user, 0);
03769                }
03770 
03771                if (musiconhold) {
03772                   ast_moh_stop(chan);
03773                } else if (!menu_mode) {
03774                   char *menu_to_play;
03775                   if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
03776                      menu_mode = MENU_ADMIN;
03777                      menu_to_play = "conf-adminmenu-18";
03778                   } else {
03779                      menu_mode = MENU_NORMAL;
03780                      menu_to_play = "conf-usermenu-162";
03781                   }
03782 
03783                   if (!ast_streamfile(chan, menu_to_play, chan->language)) {
03784                      dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
03785                      ast_stopstream(chan);
03786                   } else {
03787                      dtmf = 0;
03788                   }
03789                } else {
03790                   dtmf = f->subclass.integer;
03791                }
03792 
03793                if (dtmf > 0) {
03794                   meetme_menu(&menu_mode, &dtmf, conf, confflags, chan, user, recordingtmp, sizeof(recordingtmp), &dahdic);
03795                }
03796 
03797                if (musiconhold && !menu_mode) {
03798                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03799                }
03800 
03801                if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03802                   ast_log(LOG_WARNING, "Error setting conference\n");
03803                   close(fd);
03804                   ast_frfree(f);
03805                   goto outrun;
03806                }
03807 
03808                conf_flush(fd, chan);
03809             /*
03810              * Since options using DTMF could absorb DTMF meant for the
03811              * conference menu, we have to check them after the menu.
03812              */
03813             } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
03814                if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
03815                   conf_queue_dtmf(conf, user, f);
03816                }
03817 
03818                if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
03819                   ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
03820                   ret = 0;
03821                   ast_frfree(f);
03822                   break;
03823                } else {
03824                   ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
03825                }
03826             } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_KEYEXIT) &&
03827                (strchr(exitkeys, f->subclass.integer))) {
03828                pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
03829                   
03830                if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
03831                   conf_queue_dtmf(conf, user, f);
03832                }
03833                ret = 0;
03834                ast_frfree(f);
03835                break;
03836             } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
03837                && ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
03838                conf_queue_dtmf(conf, user, f);
03839             } else if (ast_test_flag64(confflags, CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
03840                switch (f->subclass.integer) {
03841                case AST_CONTROL_HOLD:
03842                   sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
03843                   break;
03844                default:
03845                   break;
03846                }
03847             } else if (f->frametype == AST_FRAME_NULL) {
03848                /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
03849             } else if (f->frametype == AST_FRAME_CONTROL) {
03850                switch (f->subclass.integer) {
03851                case AST_CONTROL_BUSY:
03852                case AST_CONTROL_CONGESTION:
03853                   ast_frfree(f);
03854                   goto outrun;
03855                   break;
03856                default:
03857                   ast_debug(1, 
03858                      "Got ignored control frame on channel %s, f->frametype=%d,f->subclass=%d\n",
03859                      chan->name, f->frametype, f->subclass.integer);
03860                }
03861             } else {
03862                ast_debug(1, 
03863                   "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
03864                   chan->name, f->frametype, f->subclass.integer);
03865             }
03866             ast_frfree(f);
03867          } else if (outfd > -1) {
03868             res = read(outfd, buf, CONF_SIZE);
03869             if (res > 0) {
03870                memset(&fr, 0, sizeof(fr));
03871                fr.frametype = AST_FRAME_VOICE;
03872                fr.subclass.codec = AST_FORMAT_SLINEAR;
03873                fr.datalen = res;
03874                fr.samples = res / 2;
03875                fr.data.ptr = buf;
03876                fr.offset = AST_FRIENDLY_OFFSET;
03877                if (!user->listen.actual &&
03878                   (ast_test_flag64(confflags, CONFFLAG_MONITOR) ||
03879                    (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
03880                    (!user->talking && ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER))
03881                    )) {
03882                   int idx;
03883                   for (idx = 0; idx < AST_FRAME_BITS; idx++) {
03884                      if (chan->rawwriteformat & (1 << idx)) {
03885                         break;
03886                      }
03887                   }
03888                   if (idx >= AST_FRAME_BITS) {
03889                      goto bailoutandtrynormal;
03890                   }
03891                   ast_mutex_lock(&conf->listenlock);
03892                   if (!conf->transframe[idx]) {
03893                      if (conf->origframe) {
03894                         if (musiconhold && !ast_dsp_silence(dsp, conf->origframe, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
03895                            ast_moh_stop(chan);
03896                            mohtempstopped = 1;
03897                         }
03898                         if (!conf->transpath[idx]) {
03899                            conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR);
03900                         }
03901                         if (conf->transpath[idx]) {
03902                            conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
03903                            if (!conf->transframe[idx]) {
03904                               conf->transframe[idx] = &ast_null_frame;
03905                            }
03906                         }
03907                      }
03908                   }
03909                   if (conf->transframe[idx]) {
03910                      if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
03911                          can_write(chan, confflags)) {
03912                         struct ast_frame *cur;
03913                         /* the translator may have returned a list of frames, so
03914                            write each one onto the channel
03915                         */
03916                         for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
03917                            if (ast_write(chan, cur)) {
03918                               ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
03919                               break;
03920                            }
03921                         }
03922                         if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
03923                            mohtempstopped = 0;
03924                            conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03925                         }
03926                      }
03927                   } else {
03928                      ast_mutex_unlock(&conf->listenlock);
03929                      goto bailoutandtrynormal;
03930                   }
03931                   ast_mutex_unlock(&conf->listenlock);
03932                } else {
03933 bailoutandtrynormal:
03934                   if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
03935                      ast_moh_stop(chan);
03936                      mohtempstopped = 1;
03937                   }
03938                   if (user->listen.actual) {
03939                      ast_frame_adjust_volume(&fr, user->listen.actual);
03940                   }
03941                   if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
03942                      ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
03943                   }
03944                   if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
03945                      mohtempstopped = 0;
03946                      conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03947                   }
03948                }
03949             } else {
03950                ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
03951             }
03952          }
03953          lastmarked = currentmarked;
03954       }
03955    }
03956 
03957    if (musiconhold) {
03958       ast_moh_stop(chan);
03959    }
03960    
03961    if (using_pseudo) {
03962       close(fd);
03963    } else {
03964       /* Take out of conference */
03965       dahdic.chan = 0;  
03966       dahdic.confno = 0;
03967       dahdic.confmode = 0;
03968       if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03969          ast_log(LOG_WARNING, "Error setting conference\n");
03970       }
03971    }
03972 
03973    reset_volumes(user);
03974 
03975    if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
03976       !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
03977       conf_play(chan, conf, LEAVE);
03978    }
03979 
03980    if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) || ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
03981       struct announce_listitem *item;
03982       if (!(item = ao2_alloc(sizeof(*item), NULL)))
03983          goto outrun;
03984       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
03985       ast_copy_string(item->language, chan->language, sizeof(item->language));
03986       item->confchan = conf->chan;
03987       item->confusers = conf->users;
03988       item->announcetype = CONF_HASLEFT;
03989       ast_mutex_lock(&conf->announcelistlock);
03990       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
03991       ast_cond_signal(&conf->announcelist_addition);
03992       ast_mutex_unlock(&conf->announcelistlock);
03993    } else if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
03994       ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) {
03995       /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
03996       ast_filedelete(user->namerecloc, NULL);
03997    }
03998 
03999  outrun:
04000    AST_LIST_LOCK(&confs);
04001 
04002    if (dsp) {
04003       ast_dsp_free(dsp);
04004    }
04005    
04006    if (user->user_no) {
04007       /* Only cleanup users who really joined! */
04008       now = ast_tvnow();
04009 
04010       if (sent_event) {
04011          ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeLeave",
04012             "Channel: %s\r\n"
04013             "Uniqueid: %s\r\n"
04014             "Meetme: %s\r\n"
04015             "Usernum: %d\r\n"
04016             "CallerIDNum: %s\r\n"
04017             "CallerIDName: %s\r\n"
04018             "ConnectedLineNum: %s\r\n"
04019             "ConnectedLineName: %s\r\n"
04020             "Duration: %ld\r\n",
04021             chan->name, chan->uniqueid, conf->confno,
04022             user->user_no,
04023             S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
04024             S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>"),
04025             S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
04026             S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<unknown>"),
04027             (long)(now.tv_sec - user->jointime));
04028       }
04029 
04030       if (setusercount) {
04031          conf->users--;
04032          if (rt_log_members) {
04033             /* Update table */
04034             snprintf(members, sizeof(members), "%d", conf->users);
04035             ast_realtime_require_field("meetme",
04036                "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
04037                "members", RQ_UINTEGER1, strlen(members),
04038                NULL);
04039             ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
04040          }
04041          if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
04042             conf->markedusers--;
04043          }
04044       }
04045       /* Remove ourselves from the container */
04046       ao2_unlink(conf->usercontainer, user); 
04047 
04048       /* Change any states */
04049       if (!conf->users) {
04050          ast_devstate_changed(AST_DEVICE_NOT_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
04051       }
04052 
04053       /* Return the number of seconds the user was in the conf */
04054       snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
04055       pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
04056 
04057       /* Return the RealTime bookid for CDR linking */
04058       if (rt_schedule) {
04059          pbx_builtin_setvar_helper(chan, "MEETMEBOOKID", conf->bookid);
04060       }
04061    }
04062    ao2_ref(user, -1);
04063    AST_LIST_UNLOCK(&confs);
04064 
04065    return ret;
04066 }

static void conf_start_moh ( struct ast_channel chan,
const char *  musicclass 
) [static]

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

02179 {
02180    char *original_moh;
02181 
02182    ast_channel_lock(chan);
02183    original_moh = ast_strdupa(chan->musicclass);
02184    ast_string_field_set(chan, musicclass, musicclass);
02185    ast_channel_unlock(chan);
02186 
02187    ast_moh_start(chan, original_moh, NULL);
02188 
02189    ast_channel_lock(chan);
02190    ast_string_field_set(chan, musicclass, original_moh);
02191    ast_channel_unlock(chan);
02192 }

static int count_exec ( struct ast_channel chan,
const char *  data 
) [static]

The MeetmeCount application.

Definition at line 4360 of file app_meetme.c.

References ast_channel::_state, args, 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(), ast_conference::confno, dispose_conf(), find_conf(), LOG_WARNING, pbx_builtin_setvar_helper(), and ast_conference::users.

Referenced by load_module().

04361 {
04362    int res = 0;
04363    struct ast_conference *conf;
04364    int count;
04365    char *localdata;
04366    char val[80] = "0"; 
04367    AST_DECLARE_APP_ARGS(args,
04368       AST_APP_ARG(confno);
04369       AST_APP_ARG(varname);
04370    );
04371 
04372    if (ast_strlen_zero(data)) {
04373       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
04374       return -1;
04375    }
04376    
04377    localdata = ast_strdupa(data);
04378 
04379    AST_STANDARD_APP_ARGS(args, localdata);
04380    
04381    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
04382 
04383    if (conf) {
04384       count = conf->users;
04385       dispose_conf(conf);
04386       conf = NULL;
04387    } else
04388       count = 0;
04389 
04390    if (!ast_strlen_zero(args.varname)) {
04391       /* have var so load it and exit */
04392       snprintf(val, sizeof(val), "%d", count);
04393       pbx_builtin_setvar_helper(chan, args.varname, val);
04394    } else {
04395       if (chan->_state != AST_STATE_UP) {
04396          ast_answer(chan);
04397       }
04398       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
04399    }
04400 
04401    return res;
04402 }

static struct sla_trunk_ref* create_trunk_ref ( struct sla_trunk trunk  )  [static, read]

Definition at line 6677 of file app_meetme.c.

References ao2_alloc, ao2_ref, and sla_trunk_ref_destructor().

Referenced by sla_add_trunk_to_station().

06678 {
06679    struct sla_trunk_ref *trunk_ref;
06680 
06681    if (!(trunk_ref = ao2_alloc(sizeof(*trunk_ref), sla_trunk_ref_destructor))) {
06682       return NULL;
06683    }
06684 
06685    ao2_ref(trunk, 1);
06686    trunk_ref->trunk = trunk;
06687 
06688    return trunk_ref;
06689 }

static void* dial_trunk ( void *  data  )  [static]

Definition at line 6361 of file app_meetme.c.

References ALL_TRUNK_REFS, args, ast_cond_signal, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, ast_debug, AST_DEVICE_NOT_INUSE, ast_dial_answered(), ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_run(), ast_dial_state(), ast_indicate(), ast_mutex_lock, ast_mutex_unlock, ast_party_caller_free(), ast_party_caller_init(), ast_safe_sleep(), ast_set_flag64, ast_strdupa, build_conf(), dial_trunk_args::cond, dial_trunk_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_TRUNK, dispose_conf(), MAX_CONFNUM, RAII_VAR, sla, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, dial_trunk_args::station, and dial_trunk_args::trunk_ref.

Referenced by sla_station_exec().

06362 {
06363    struct dial_trunk_args *args = data;
06364    struct ast_dial *dial;
06365    char *tech, *tech_data;
06366    enum ast_dial_result dial_res;
06367    char conf_name[MAX_CONFNUM];
06368    struct ast_conference *conf;
06369    struct ast_flags64 conf_flags = { 0 };
06370    RAII_VAR(struct sla_trunk_ref *, trunk_ref, args->trunk_ref, unref_obj);
06371    RAII_VAR(struct sla_station *, station, args->station, unref_obj);
06372    int caller_is_saved;
06373    struct ast_party_caller caller;
06374    int last_state = 0;
06375    int current_state = 0;
06376 
06377    if (!(dial = ast_dial_create())) {
06378       ast_mutex_lock(args->cond_lock);
06379       ast_cond_signal(args->cond);
06380       ast_mutex_unlock(args->cond_lock);
06381       return NULL;
06382    }
06383 
06384    tech_data = ast_strdupa(trunk_ref->trunk->device);
06385    tech = strsep(&tech_data, "/");
06386    if (ast_dial_append(dial, tech, tech_data) == -1) {
06387       ast_mutex_lock(args->cond_lock);
06388       ast_cond_signal(args->cond);
06389       ast_mutex_unlock(args->cond_lock);
06390       ast_dial_destroy(dial);
06391       return NULL;
06392    }
06393 
06394    /* Do we need to save of the caller ID data? */
06395    caller_is_saved = 0;
06396    if (!sla.attempt_callerid) {
06397       caller_is_saved = 1;
06398       caller = trunk_ref->chan->caller;
06399       ast_party_caller_init(&trunk_ref->chan->caller);
06400    }
06401 
06402    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
06403 
06404    /* Restore saved caller ID */
06405    if (caller_is_saved) {
06406       ast_party_caller_free(&trunk_ref->chan->caller);
06407       trunk_ref->chan->caller = caller;
06408    }
06409 
06410    if (dial_res != AST_DIAL_RESULT_TRYING) {
06411       ast_mutex_lock(args->cond_lock);
06412       ast_cond_signal(args->cond);
06413       ast_mutex_unlock(args->cond_lock);
06414       ast_dial_destroy(dial);
06415       return NULL;
06416    }
06417 
06418    for (;;) {
06419       unsigned int done = 0;
06420       switch ((dial_res = ast_dial_state(dial))) {
06421       case AST_DIAL_RESULT_ANSWERED:
06422          trunk_ref->trunk->chan = ast_dial_answered(dial);
06423       case AST_DIAL_RESULT_HANGUP:
06424       case AST_DIAL_RESULT_INVALID:
06425       case AST_DIAL_RESULT_FAILED:
06426       case AST_DIAL_RESULT_TIMEOUT:
06427       case AST_DIAL_RESULT_UNANSWERED:
06428          done = 1;
06429          break;
06430       case AST_DIAL_RESULT_TRYING:
06431          current_state = AST_CONTROL_PROGRESS;
06432          break;
06433       case AST_DIAL_RESULT_RINGING:
06434       case AST_DIAL_RESULT_PROGRESS:
06435       case AST_DIAL_RESULT_PROCEEDING:
06436          current_state = AST_CONTROL_RINGING;
06437          break;
06438       }
06439       if (done)
06440          break;
06441 
06442       /* check that SLA station that originated trunk call is still alive */
06443       if (station && ast_device_state(station->device) == AST_DEVICE_NOT_INUSE) {
06444          ast_debug(3, "Originating station device %s no longer active\n", station->device);
06445          trunk_ref->trunk->chan = NULL;
06446          break;
06447       }
06448 
06449       /* If trunk line state changed, send indication back to originating SLA Station channel */
06450       if (current_state != last_state) {
06451          ast_debug(3, "Indicating State Change %d to channel %s\n", current_state, trunk_ref->chan->name);
06452          ast_indicate(trunk_ref->chan, current_state);
06453          last_state = current_state;
06454       }
06455 
06456       /* avoid tight loop... sleep for 1/10th second */
06457       ast_safe_sleep(trunk_ref->chan, 100);
06458    }
06459 
06460    if (!trunk_ref->trunk->chan) {
06461       ast_mutex_lock(args->cond_lock);
06462       ast_cond_signal(args->cond);
06463       ast_mutex_unlock(args->cond_lock);
06464       ast_dial_join(dial);
06465       ast_dial_destroy(dial);
06466       return NULL;
06467    }
06468 
06469    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
06470    ast_set_flag64(&conf_flags, 
06471       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
06472       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
06473    conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan, NULL);
06474 
06475    ast_mutex_lock(args->cond_lock);
06476    ast_cond_signal(args->cond);
06477    ast_mutex_unlock(args->cond_lock);
06478 
06479    if (conf) {
06480       conf_run(trunk_ref->trunk->chan, conf, &conf_flags, NULL);
06481       dispose_conf(conf);
06482       conf = NULL;
06483    }
06484 
06485    /* If the trunk is going away, it is definitely now IDLE. */
06486    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06487 
06488    trunk_ref->trunk->chan = NULL;
06489    trunk_ref->trunk->on_hold = 0;
06490 
06491    ast_dial_join(dial);
06492    ast_dial_destroy(dial);
06493 
06494    return NULL;
06495 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Decrement reference counts, as incremented by find_conf().

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

02098 {
02099    int res = 0;
02100    int confno_int = 0;
02101 
02102    AST_LIST_LOCK(&confs);
02103    if (ast_atomic_dec_and_test(&conf->refcount)) {
02104       /* Take the conference room number out of an inuse state */
02105       if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
02106          conf_map[confno_int] = 0;
02107       }
02108       conf_free(conf);
02109       res = 1;
02110    }
02111    AST_LIST_UNLOCK(&confs);
02112 
02113    return res;
02114 }

static void filename_parse ( char *  filename,
char *  buffer 
) [static]

Definition at line 5172 of file app_meetme.c.

References ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_log(), ast_mkdir(), ast_strlen_zero(), and LOG_WARNING.

Referenced by recordthread().

05173 {
05174    char *slash;
05175    if (ast_strlen_zero(filename)) {
05176       ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
05177    } else if (filename[0] != '/') {
05178       snprintf(buffer, PATH_MAX, "%s/meetme/%s", ast_config_AST_SPOOL_DIR, filename);
05179    } else {
05180       ast_copy_string(buffer, filename, PATH_MAX);
05181    }
05182 
05183    slash = buffer;
05184    if ((slash = strrchr(slash, '/'))) {
05185       *slash = '\0';
05186       ast_mkdir(buffer, 0777);
05187       *slash = '/';
05188    }
05189 }

static struct ast_conference* find_conf ( struct ast_channel chan,
char *  confno,
int  make,
int  dynamic,
char *  dynamic_pin,
size_t  pin_buf_len,
int  refcount,
struct ast_flags64 confflags 
) [static, read]

Definition at line 4256 of file app_meetme.c.

References args, AST_APP_ARG, ast_app_getdata(), ast_clear_flag64, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_test_flag64, ast_variable_browse(), build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_conference::confno, LOG_ERROR, LOG_WARNING, MAX_SETTINGS, ast_variable::name, ast_variable::next, parse(), ast_conference::pin, ast_conference::pinadmin, ast_conference::refcount, S_OR, ast_variable::value, and var.

Referenced by conf_exec(), and count_exec().

04258 {
04259    struct ast_config *cfg;
04260    struct ast_variable *var;
04261    struct ast_flags config_flags = { 0 };
04262    struct ast_conference *cnf;
04263 
04264    AST_DECLARE_APP_ARGS(args,
04265       AST_APP_ARG(confno);
04266       AST_APP_ARG(pin);
04267       AST_APP_ARG(pinadmin);
04268    );
04269 
04270    /* Check first in the conference list */
04271    ast_debug(1, "The requested confno is '%s'?\n", confno);
04272    AST_LIST_LOCK(&confs);
04273    AST_LIST_TRAVERSE(&confs, cnf, list) {
04274       ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
04275       if (!strcmp(confno, cnf->confno)) 
04276          break;
04277    }
04278    if (cnf) {
04279       cnf->refcount += refcount;
04280    }
04281    AST_LIST_UNLOCK(&confs);
04282 
04283    if (!cnf) {
04284       if (dynamic) {
04285          /* No need to parse meetme.conf */
04286          ast_debug(1, "Building dynamic conference '%s'\n", confno);
04287          if (dynamic_pin) {
04288             if (dynamic_pin[0] == 'q') {
04289                /* Query the user to enter a PIN */
04290                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
04291                   return NULL;
04292             }
04293             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan, NULL);
04294          } else {
04295             cnf = build_conf(confno, "", "", make, dynamic, refcount, chan, NULL);
04296          }
04297       } else {
04298          /* Check the config */
04299          cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
04300          if (!cfg) {
04301             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
04302             return NULL;
04303          } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04304             ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
04305             return NULL;
04306          }
04307 
04308          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
04309             char parse[MAX_SETTINGS];
04310 
04311             if (strcasecmp(var->name, "conf"))
04312                continue;
04313 
04314             ast_copy_string(parse, var->value, sizeof(parse));
04315 
04316             AST_STANDARD_APP_ARGS(args, parse);
04317             ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
04318             if (!strcasecmp(args.confno, confno)) {
04319                /* Bingo it's a valid conference */
04320                cnf = build_conf(args.confno,
04321                      S_OR(args.pin, ""),
04322                      S_OR(args.pinadmin, ""),
04323                      make, dynamic, refcount, chan, NULL);
04324                break;
04325             }
04326          }
04327          if (!var) {
04328             ast_debug(1, "%s isn't a valid conference\n", confno);
04329          }
04330          ast_config_destroy(cfg);
04331       }
04332    } else if (dynamic_pin) {
04333       /* Correct for the user selecting 'D' instead of 'd' to have
04334          someone join into a conference that has already been created
04335          with a pin. */
04336       if (dynamic_pin[0] == 'q') {
04337          dynamic_pin[0] = '\0';
04338       }
04339    }
04340 
04341    if (cnf) {
04342       if (confflags && !cnf->chan &&
04343           !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
04344           ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
04345          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
04346          ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
04347       }
04348       
04349       if (confflags && !cnf->chan &&
04350           ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
04351          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
04352          ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
04353       }
04354    }
04355 
04356    return cnf;
04357 }

static struct ast_conference* find_conf_realtime ( struct ast_channel chan,
char *  confno,
int  make,
int  dynamic,
char *  dynamic_pin,
size_t  pin_buf_len,
int  refcount,
struct ast_flags64 confflags,
int *  too_early,
char **  optargs 
) [static, read]

Definition at line 4068 of file app_meetme.c.

References ast_conference::adminopts, ast_app_parse_options64(), ast_channel_lock, ast_channel_unlock, ast_clear_flag64, ast_copy_flags64, ast_copy_string(), ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), AST_MAX_EXTENSION, ast_mktime(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_test_flag64, ast_tvnow(), ast_variables_destroy(), ast_verb, ast_waitstream(), ast_conference::bookid, build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, ast_conference::confno, DATE_FORMAT, ast_conference::endalert, ast_conference::endtime, ast_flags64::flags, LOG_WARNING, ast_conference::maxusers, ast_variable::name, ast_variable::next, OPTIONS_LEN, pbx_builtin_getvar_helper(), ast_conference::pin, ast_conference::pinadmin, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::refcount, ast_conference::useropts, ast_variable::value, and var.

Referenced by conf_exec().

04070 {
04071    struct ast_variable *var, *origvar;
04072    struct ast_conference *cnf;
04073 
04074    *too_early = 0;
04075 
04076    /* Check first in the conference list */
04077    AST_LIST_LOCK(&confs);
04078    AST_LIST_TRAVERSE(&confs, cnf, list) {
04079       if (!strcmp(confno, cnf->confno)) {
04080          break;
04081       }
04082    }
04083    if (cnf) {
04084       cnf->refcount += refcount;
04085    }
04086    AST_LIST_UNLOCK(&confs);
04087 
04088    if (!cnf) {
04089       char *pin = NULL, *pinadmin = NULL; /* For temp use */
04090       int maxusers = 0;
04091       struct timeval now;
04092       char recordingfilename[256] = "";
04093       char recordingformat[11] = "";
04094       char currenttime[32] = "";
04095       char eatime[32] = "";
04096       char bookid[51] = "";
04097       char recordingtmp[AST_MAX_EXTENSION] = "";
04098       char useropts[OPTIONS_LEN + 1] = ""; /* Used for RealTime conferences */
04099       char adminopts[OPTIONS_LEN + 1] = "";
04100       struct ast_tm tm, etm;
04101       struct timeval endtime = { .tv_sec = 0 };
04102       const char *var2;
04103 
04104       if (rt_schedule) {
04105          now = ast_tvnow();
04106 
04107          ast_localtime(&now, &tm, NULL);
04108          ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
04109 
04110          ast_debug(1, "Looking for conference %s that starts after %s\n", confno, currenttime);
04111 
04112          var = ast_load_realtime("meetme", "confno",
04113             confno, "starttime <= ", currenttime, "endtime >= ",
04114             currenttime, NULL);
04115 
04116          if (!var && fuzzystart) {
04117             now = ast_tvnow();
04118             now.tv_sec += fuzzystart;
04119 
04120             ast_localtime(&now, &tm, NULL);
04121             ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
04122             var = ast_load_realtime("meetme", "confno",
04123                confno, "starttime <= ", currenttime, "endtime >= ",
04124                currenttime, NULL);
04125          }
04126 
04127          if (!var && earlyalert) {
04128             now = ast_tvnow();
04129             now.tv_sec += earlyalert;
04130             ast_localtime(&now, &etm, NULL);
04131             ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
04132             var = ast_load_realtime("meetme", "confno",
04133                confno, "starttime <= ", eatime, "endtime >= ",
04134                currenttime, NULL);
04135             if (var) {
04136                *too_early = 1;
04137             }
04138          }
04139 
04140       } else {
04141           var = ast_load_realtime("meetme", "confno", confno, NULL);
04142       }
04143 
04144       if (!var) {
04145          return NULL;
04146       }
04147 
04148       if (rt_schedule && *too_early) {
04149          /* Announce that the caller is early and exit */
04150          if (!ast_streamfile(chan, "conf-has-not-started", chan->language)) {
04151             ast_waitstream(chan, "");
04152          }
04153          ast_variables_destroy(var);
04154          return NULL;
04155       }
04156 
04157       for (origvar = var; var; var = var->next) {
04158          if (!strcasecmp(var->name, "pin")) {
04159             pin = ast_strdupa(var->value);
04160          } else if (!strcasecmp(var->name, "adminpin")) {
04161             pinadmin = ast_strdupa(var->value);
04162          } else if (!strcasecmp(var->name, "bookId")) {
04163             ast_copy_string(bookid, var->value, sizeof(bookid));
04164          } else if (!strcasecmp(var->name, "opts")) {
04165             ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
04166          } else if (!strcasecmp(var->name, "maxusers")) {
04167             maxusers = atoi(var->value);
04168          } else if (!strcasecmp(var->name, "adminopts")) {
04169             ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
04170          } else if (!strcasecmp(var->name, "recordingfilename")) {
04171             ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
04172          } else if (!strcasecmp(var->name, "recordingformat")) {
04173             ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
04174          } else if (!strcasecmp(var->name, "endtime")) {
04175             struct ast_tm endtime_tm;
04176             ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
04177             endtime = ast_mktime(&endtime_tm, NULL);
04178          }
04179       }
04180 
04181       ast_variables_destroy(origvar);
04182 
04183       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan, NULL);
04184 
04185       if (cnf) {
04186          struct ast_flags64 tmp_flags;
04187 
04188          cnf->maxusers = maxusers;
04189          cnf->endalert = endalert;
04190          cnf->endtime = endtime.tv_sec;
04191          cnf->useropts = ast_strdup(useropts);
04192          cnf->adminopts = ast_strdup(adminopts);
04193          cnf->bookid = ast_strdup(bookid);
04194          if (!ast_strlen_zero(recordingfilename)) {
04195             cnf->recordingfilename = ast_strdup(recordingfilename);
04196          }
04197          if (!ast_strlen_zero(recordingformat)) {
04198             cnf->recordingformat = ast_strdup(recordingformat);
04199          }
04200 
04201          /* Parse the other options into confflags -- need to do this in two
04202           * steps, because the parse_options routine zeroes the buffer. */
04203          ast_app_parse_options64(meetme_opts, &tmp_flags, optargs, useropts);
04204          ast_copy_flags64(confflags, &tmp_flags, tmp_flags.flags);
04205 
04206          if (strchr(cnf->useropts, 'r')) {
04207             if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */
04208                ast_channel_lock(chan);
04209                if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
04210                   ast_free(cnf->recordingfilename);
04211                   cnf->recordingfilename = ast_strdup(var2);
04212                }
04213                ast_channel_unlock(chan);
04214                if (ast_strlen_zero(cnf->recordingfilename)) {
04215                   snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, chan->uniqueid);
04216                   ast_free(cnf->recordingfilename);
04217                   cnf->recordingfilename = ast_strdup(recordingtmp);
04218                }
04219             }
04220             if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */
04221                ast_channel_lock(chan);
04222                if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
04223                   ast_free(cnf->recordingformat);
04224                   cnf->recordingformat = ast_strdup(var2);
04225                }
04226                ast_channel_unlock(chan);
04227                if (ast_strlen_zero(cnf->recordingformat)) {
04228                   ast_free(cnf->recordingformat);
04229                   cnf->recordingformat = ast_strdup("wav");
04230                }
04231             }
04232             ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
04233          }
04234       }
04235    }
04236 
04237    if (cnf) {
04238       if (confflags->flags && !cnf->chan &&
04239           !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
04240           ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
04241          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
04242          ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
04243       }
04244 
04245       if (confflags && !cnf->chan &&
04246           ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
04247          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
04248          ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
04249       }
04250    }
04251 
04252    return cnf;
04253 }

static struct ast_conf_user* find_user ( struct ast_conference conf,
const char *  callerident 
) [static, read]

Definition at line 4730 of file app_meetme.c.

References ao2_find, and ast_conference::usercontainer.

Referenced by admin_exec().

04731 {
04732    struct ast_conf_user *user = NULL;
04733    int cid;
04734 
04735    if (conf && callerident && sscanf(callerident, "%30d", &cid) == 1) {
04736       user = ao2_find(conf->usercontainer, &cid, 0);
04737       /* reference decremented later in admin_exec */
04738       return user;
04739    }
04740    return NULL;
04741 }

static const char* get_announce_filename ( enum announcetypes  type  )  [static]

Definition at line 2194 of file app_meetme.c.

References CONF_HASJOIN, and CONF_HASLEFT.

Referenced by announce_thread().

02195 {
02196    switch (type) {
02197    case CONF_HASLEFT:
02198       return "conf-hasleft";
02199       break;
02200    case CONF_HASJOIN:
02201       return "conf-hasjoin";
02202       break;
02203    default:
02204       return "";
02205    }
02206 }

static const char* istalking ( int  x  )  [static]

Definition at line 1006 of file app_meetme.c.

Referenced by meetme_show_cmd().

01007 {
01008    if (x > 0)
01009       return "(talking)";
01010    else if (x < 0)
01011       return "(unmonitored)";
01012    else 
01013       return "(not talking)";
01014 }

static int load_config ( int  reload  )  [static]

Definition at line 7521 of file app_meetme.c.

References load_config_meetme(), and sla_load_config().

Referenced by load_module(), and reload().

07522 {
07523    load_config_meetme();
07524    return sla_load_config(reload);
07525 }

static void load_config_meetme ( void   )  [static]

Definition at line 5282 of file app_meetme.c.

References ast_config_destroy(), ast_config_load, ast_log(), ast_true(), ast_variable_retrieve(), CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, DEFAULT_AUDIO_BUFFERS, LOG_ERROR, LOG_NOTICE, and LOG_WARNING.

Referenced by load_config().

05283 {
05284    struct ast_config *cfg;
05285    struct ast_flags config_flags = { 0 };
05286    const char *val;
05287 
05288    if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
05289       return;
05290    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
05291       ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
05292       return;
05293    }
05294 
05295    audio_buffers = DEFAULT_AUDIO_BUFFERS;
05296 
05297    /*  Scheduling support is off by default */
05298    rt_schedule = 0;
05299    fuzzystart = 0;
05300    earlyalert = 0;
05301    endalert = 0;
05302    extendby = 0;
05303 
05304    /*  Logging of participants defaults to ON for compatibility reasons */
05305    rt_log_members = 1;  
05306 
05307    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
05308       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
05309          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
05310          audio_buffers = DEFAULT_AUDIO_BUFFERS;
05311       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
05312          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
05313             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
05314          audio_buffers = DEFAULT_AUDIO_BUFFERS;
05315       }
05316       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
05317          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
05318    }
05319 
05320    if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
05321       rt_schedule = ast_true(val);
05322    if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
05323       rt_log_members = ast_true(val);
05324    if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
05325       if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
05326          ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
05327          fuzzystart = 0;
05328       } 
05329    }
05330    if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
05331       if ((sscanf(val, "%30d", &earlyalert) != 1)) {
05332          ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
05333          earlyalert = 0;
05334       } 
05335    }
05336    if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
05337       if ((sscanf(val, "%30d", &endalert) != 1)) {
05338          ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
05339          endalert = 0;
05340       } 
05341    }
05342    if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
05343       if ((sscanf(val, "%30d", &extendby) != 1)) {
05344          ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
05345          extendby = 0;
05346       } 
05347    }
05348 
05349    ast_config_destroy(cfg);
05350 }

static int load_module ( void   )  [static]

Definition at line 7736 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_data_register_multiple, ast_devstate_prov_add(), ast_manager_register_xml, ast_realtime_require_field(), ast_register_application_xml, AST_TEST_REGISTER, channel_admin_exec(), conf_exec(), count_exec(), EVENT_FLAG_CALL, EVENT_FLAG_REPORTING, load_config(), meetmestate(), RQ_UINTEGER1, RQ_UINTEGER2, sla_state(), sla_station_exec(), and sla_trunk_exec().

07737 {
07738    int res = 0;
07739 
07740    res |= load_config(0);
07741 
07742    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07743    res |= ast_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute);
07744    res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute);
07745    res |= ast_manager_register_xml("MeetmeList", EVENT_FLAG_REPORTING, action_meetmelist);
07746    res |= ast_register_application_xml(app4, channel_admin_exec);
07747    res |= ast_register_application_xml(app3, admin_exec);
07748    res |= ast_register_application_xml(app2, count_exec);
07749    res |= ast_register_application_xml(app, conf_exec);
07750    res |= ast_register_application_xml(slastation_app, sla_station_exec);
07751    res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
07752 
07753 #ifdef TEST_FRAMEWORK
07754    AST_TEST_REGISTER(test_meetme_data_provider);
07755 #endif
07756    ast_data_register_multiple(meetme_data_providers, ARRAY_LEN(meetme_data_providers));
07757 
07758    res |= ast_devstate_prov_add("Meetme", meetmestate);
07759    res |= ast_devstate_prov_add("SLA", sla_state);
07760 
07761    res |= ast_custom_function_register(&meetme_info_acf);
07762    ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
07763 
07764    return res;
07765 }

static char* meetme_cmd_helper ( struct ast_cli_args a  )  [static]

Definition at line 1594 of file app_meetme.c.

References admin_exec(), ast_cli_args::argv, ast_debug, ast_free, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), CLI_FAILURE, CLI_SHOWUSAGE, CLI_SUCCESS, and MAX_CONFNUM.

Referenced by meetme_kick_cmd(), meetme_lock_cmd(), and meetme_mute_cmd().

01595 {
01596    /* Process the command */
01597    struct ast_str *cmdline;
01598 
01599    /* Max confno length */
01600    if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01601       return CLI_FAILURE;
01602    }
01603 
01604    ast_str_set(&cmdline, 0, "%s", a->argv[2]);  /* Argv 2: conference number */
01605    if (strcasestr(a->argv[1], "lock")) {
01606       if (strcasecmp(a->argv[1], "lock") == 0) {
01607          /* Lock */
01608          ast_str_append(&cmdline, 0, ",L");
01609       } else {
01610          /* Unlock */
01611          ast_str_append(&cmdline, 0, ",l");
01612       }
01613    } else if (strcasestr(a->argv[1], "mute")) { 
01614       if (strcasecmp(a->argv[1], "mute") == 0) {
01615          /* Mute */
01616          if (strcasecmp(a->argv[3], "all") == 0) {
01617             ast_str_append(&cmdline, 0, ",N");
01618          } else {
01619             ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);  
01620          }
01621       } else {
01622          /* Unmute */
01623          if (strcasecmp(a->argv[3], "all") == 0) {
01624             ast_str_append(&cmdline, 0, ",n");
01625          } else {
01626             ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
01627          }
01628       }
01629    } else if (strcasecmp(a->argv[1], "kick") == 0) {
01630       if (strcasecmp(a->argv[3], "all") == 0) {
01631          /* Kick all */
01632          ast_str_append(&cmdline, 0, ",K");
01633       } else {
01634          /* Kick a single user */
01635          ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
01636       }
01637    } else {
01638       /*
01639        * Should never get here because it is already filtered by the
01640        * callers.
01641        */
01642       ast_free(cmdline);
01643       return CLI_SHOWUSAGE;
01644    }
01645 
01646    ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
01647 
01648    admin_exec(NULL, ast_str_buffer(cmdline));
01649    ast_free(cmdline);
01650 
01651    return CLI_SUCCESS;
01652 }

static int meetme_data_provider_get ( const struct ast_data_search search,
struct ast_data data_root 
) [static]

Definition at line 7602 of file app_meetme.c.

References ao2_callback, ao2_container_count(), ast_data_add_node(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, OBJ_NODATA, user_add_provider_cb(), and ast_conference::usercontainer.

07604 {
07605    struct ast_conference *cnf;
07606    struct ast_data *data_meetme, *data_meetme_users;
07607 
07608    AST_LIST_LOCK(&confs);
07609    AST_LIST_TRAVERSE(&confs, cnf, list) {
07610       data_meetme = ast_data_add_node(data_root, "meetme");
07611       if (!data_meetme) {
07612          continue;
07613       }
07614 
07615       ast_data_add_structure(ast_conference, data_meetme, cnf);
07616 
07617       if (ao2_container_count(cnf->usercontainer)) {
07618          data_meetme_users = ast_data_add_node(data_meetme, "users");
07619          if (!data_meetme_users) {
07620             ast_data_remove_node(data_root, data_meetme);
07621             continue;
07622          }
07623 
07624          ao2_callback(cnf->usercontainer, OBJ_NODATA, user_add_provider_cb, data_meetme_users); 
07625       }
07626 
07627       if (!ast_data_search_match(search, data_meetme)) {
07628          ast_data_remove_node(data_root, data_meetme);
07629       }
07630    }
07631    AST_LIST_UNLOCK(&confs);
07632 
07633    return 0;
07634 }

static char* meetme_kick_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1674 of file app_meetme.c.

References ast_cli_args::argc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_meetmecmd_mute_kick(), ast_cli_args::line, meetme_cmd_helper(), ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

01675 {
01676    switch (cmd) {
01677    case CLI_INIT:
01678       e->command = "meetme kick";
01679       e->usage =
01680          "Usage: meetme kick <confno> all|<userno>\n"
01681          "       Kick a conference or a user in a conference.\n";
01682       return NULL;
01683    case CLI_GENERATE:
01684       return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
01685    }
01686 
01687    if (a->argc != 4) {
01688       return CLI_SHOWUSAGE;
01689    }
01690 
01691    return meetme_cmd_helper(a);
01692 }

static char* meetme_lock_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1654 of file app_meetme.c.

References ast_cli_args::argc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_meetmecmd_lock(), meetme_cmd_helper(), ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

01655 {
01656    switch (cmd) {
01657    case CLI_INIT:
01658       e->command = "meetme {lock|unlock}";
01659       e->usage =
01660          "Usage: meetme lock|unlock <confno>\n"
01661          "       Lock or unlock a conference to new users.\n";
01662       return NULL;
01663    case CLI_GENERATE:
01664       return complete_meetmecmd_lock(a->word, a->pos, a->n);
01665    }
01666 
01667    if (a->argc != 3) {
01668       return CLI_SHOWUSAGE;
01669    }
01670 
01671    return meetme_cmd_helper(a);
01672 }

static void meetme_menu ( enum menu_modes menu_mode,
int *  dtmf,
struct ast_conference conf,
struct ast_flags64 confflags,
struct ast_channel chan,
struct ast_conf_user user,
char *  recordingtmp,
int  recordingtmp_size,
struct dahdi_confinfo *  dahdic 
) [static]

Definition at line 2734 of file app_meetme.c.

References meetme_menu_admin(), meetme_menu_admin_extended(), meetme_menu_normal(), MENU_ADMIN, MENU_ADMIN_EXTENDED, MENU_DISABLED, and MENU_NORMAL.

Referenced by conf_run().

02735 {
02736    switch (*menu_mode) {
02737    case MENU_DISABLED:
02738       break;
02739    case MENU_NORMAL:
02740       meetme_menu_normal(menu_mode, dtmf, conf, confflags, chan, user);
02741       break;
02742    case MENU_ADMIN:
02743       meetme_menu_admin(menu_mode, dtmf, conf, confflags, chan, user);
02744       /* Admin Menu is capable of branching into another menu, in which case it will reset dtmf and change the menu mode. */
02745       if (*menu_mode != MENU_ADMIN_EXTENDED || (*dtmf <= 0)) {
02746          break;
02747       }
02748    case MENU_ADMIN_EXTENDED:
02749       meetme_menu_admin_extended(menu_mode, dtmf, conf, confflags, chan, user, recordingtmp, recordingtmp_size, dahdic);
02750       break;
02751    }
02752 }

static void meetme_menu_admin ( enum menu_modes menu_mode,
int *  dtmf,
struct ast_conference conf,
struct ast_flags64 confflags,
struct ast_channel chan,
struct ast_conf_user user 
) [static]

Definition at line 2429 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, ao2_callback, ao2_find, ao2_ref, AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_test_flag64, ast_waitstream(), ast_conf_user::chan, CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_conference::locked, MENU_ADMIN_EXTENDED, MENU_DISABLED, OBJ_NODATA, rt_extend_conf(), tweak_listen_volume(), tweak_talk_volume(), user_max_cmp(), ast_conference::usercontainer, ast_conf_user::userflags, VOL_DOWN, and VOL_UP.

Referenced by meetme_menu().

02430 {
02431    switch(*dtmf) {
02432    case '1': /* Un/Mute */
02433       *menu_mode = MENU_DISABLED;
02434       /* for admin, change both admin and use flags */
02435       if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
02436          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02437       } else {
02438          user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02439       }
02440 
02441       if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02442          if (!ast_streamfile(chan, "conf-muted", chan->language)) {
02443             ast_waitstream(chan, "");
02444          }
02445       } else {
02446          if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
02447             ast_waitstream(chan, "");
02448          }
02449       }
02450       break;
02451 
02452    case '2': /* Un/Lock the Conference */
02453       *menu_mode = MENU_DISABLED;
02454       if (conf->locked) {
02455          conf->locked = 0;
02456          if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) {
02457             ast_waitstream(chan, "");
02458          }
02459       } else {
02460          conf->locked = 1;
02461          if (!ast_streamfile(chan, "conf-lockednow", chan->language)) {
02462             ast_waitstream(chan, "");
02463          }
02464       }
02465       break;
02466 
02467    case '3': /* Eject last user */
02468    {
02469       struct ast_conf_user *usr = NULL;
02470       int max_no = 0;
02471       ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
02472       *menu_mode = MENU_DISABLED;
02473       usr = ao2_find(conf->usercontainer, &max_no, 0);
02474       if ((usr->chan->name == chan->name) || ast_test_flag64(&usr->userflags, CONFFLAG_ADMIN)) {
02475          if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
02476             ast_waitstream(chan, "");
02477          }
02478       } else {
02479          usr->adminflags |= ADMINFLAG_KICKME;
02480       }
02481       ao2_ref(usr, -1);
02482       ast_stopstream(chan);
02483       break;
02484    }
02485 
02486    case '4':
02487       tweak_listen_volume(user, VOL_DOWN);
02488       break;
02489 
02490    case '5':
02491       /* Extend RT conference */
02492       if (rt_schedule) {
02493          if (!rt_extend_conf(conf->confno)) {
02494             if (!ast_streamfile(chan, "conf-extended", chan->language)) {
02495                ast_waitstream(chan, "");
02496             }
02497          } else {
02498             if (!ast_streamfile(chan, "conf-nonextended", chan->language)) {
02499                ast_waitstream(chan, "");
02500             }
02501          }
02502          ast_stopstream(chan);
02503       }
02504       *menu_mode = MENU_DISABLED;
02505       break;
02506 
02507    case '6':
02508       tweak_listen_volume(user, VOL_UP);
02509       break;
02510 
02511    case '7':
02512       tweak_talk_volume(user, VOL_DOWN);
02513       break;
02514 
02515    case '8':
02516       if (!ast_streamfile(chan, "conf-adminmenu-menu8", chan->language)) {
02517          /* If the user provides DTMF while playing the sound, we want to drop right into the extended menu function with new DTMF once we get out of here. */
02518          *dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02519          ast_stopstream(chan);
02520       }
02521       *menu_mode = MENU_ADMIN_EXTENDED;
02522       break;
02523 
02524    case '9':
02525       tweak_talk_volume(user, VOL_UP);
02526       break;
02527    default:
02528       menu_mode = MENU_DISABLED;
02529       /* Play an error message! */
02530       if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
02531          ast_waitstream(chan, "");
02532       }
02533       break;
02534    }
02535 
02536 }

static void meetme_menu_admin_extended ( enum menu_modes menu_mode,
int *  dtmf,
struct ast_conference conf,
struct ast_flags64 confflags,
struct ast_channel chan,
struct ast_conf_user user,
char *  recordingtmp,
int  recordingtmp_size,
struct dahdi_confinfo *  dahdic 
) [static]

Definition at line 2550 of file app_meetme.c.

References ao2_callback, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_lock, ast_channel_unlock, AST_DIGIT_ANY, ast_fileexists(), AST_FORMAT_SLINEAR, ast_hangup(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_request(), ast_say_number(), ast_set_flag64, ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdup, ast_streamfile(), ast_test_flag64, ast_verb, ast_waitstream(), CONFFLAG_RECORDCONF, ast_conference::confno, ast_conference::dahdiconf, ast_channel::fds, ast_conference::gmuted, ast_conference::lchan, LOG_WARNING, MEETME_RECORD_ACTIVE, MENU_DISABLED, ast_conf_user::namerecloc, OBJ_NODATA, pbx_builtin_getvar_helper(), ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, user_set_kickme_cb(), user_set_muted_cb(), user_set_unmuted_cb(), ast_conference::usercontainer, ast_conference::users, and var.

Referenced by meetme_menu().

02551 {
02552    int keepplaying;
02553    int playednamerec;
02554    int res;
02555    struct ao2_iterator user_iter;
02556    struct ast_conf_user *usr = NULL;
02557 
02558    switch(*dtmf) {
02559    case '1': /* *81 Roll call */
02560       keepplaying = 1;
02561       playednamerec = 0;
02562       if (conf->users == 1) {
02563          if (keepplaying && !ast_streamfile(chan, "conf-onlyperson", chan->language)) {
02564             res = ast_waitstream(chan, AST_DIGIT_ANY);
02565             ast_stopstream(chan);
02566             if (res > 0) {
02567                keepplaying = 0;
02568             }
02569          }
02570       } else if (conf->users == 2) {
02571          if (keepplaying && !ast_streamfile(chan, "conf-onlyone", chan->language)) {
02572             res = ast_waitstream(chan, AST_DIGIT_ANY);
02573             ast_stopstream(chan);
02574             if (res > 0) {
02575                keepplaying = 0;
02576             }
02577          }
02578       } else {
02579          if (keepplaying && !ast_streamfile(chan, "conf-thereare", chan->language)) {
02580             res = ast_waitstream(chan, AST_DIGIT_ANY);
02581             ast_stopstream(chan);
02582             if (res > 0) {
02583                keepplaying = 0;
02584             }
02585          }
02586          if (keepplaying) {
02587             res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
02588             ast_stopstream(chan);
02589             if (res > 0) {
02590                keepplaying = 0;
02591             }
02592          }
02593          if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
02594             res = ast_waitstream(chan, AST_DIGIT_ANY);
02595             ast_stopstream(chan);
02596             if (res > 0) {
02597                keepplaying = 0;
02598             }
02599          }
02600       }
02601       user_iter = ao2_iterator_init(conf->usercontainer, 0);
02602       while((usr = ao2_iterator_next(&user_iter))) {
02603          if (ast_fileexists(usr->namerecloc, NULL, NULL)) {
02604             if (keepplaying && !ast_streamfile(chan, usr->namerecloc, chan->language)) {
02605                res = ast_waitstream(chan, AST_DIGIT_ANY);
02606                ast_stopstream(chan);
02607                if (res > 0) {
02608                   keepplaying = 0;
02609                }
02610             }
02611             playednamerec = 1;
02612          }
02613          ao2_ref(usr, -1);
02614       }
02615       ao2_iterator_destroy(&user_iter);
02616       if (keepplaying && playednamerec && !ast_streamfile(chan, "conf-roll-callcomplete", chan->language)) {
02617          res = ast_waitstream(chan, AST_DIGIT_ANY);
02618          ast_stopstream(chan);
02619          if (res > 0) {
02620             keepplaying = 0;
02621          }
02622       }
02623 
02624       *menu_mode = MENU_DISABLED;
02625       break;
02626 
02627    case '2': /* *82 Eject all non-admins */
02628       if (conf->users == 1) {
02629          if(!ast_streamfile(chan, "conf-errormenu", chan->language)) {
02630             ast_waitstream(chan, "");
02631          }
02632       } else {
02633          ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_kickme_cb, &conf);
02634       }
02635       ast_stopstream(chan);
02636       *menu_mode = MENU_DISABLED;
02637       break;
02638 
02639    case '3': /* *83 (Admin) mute/unmute all non-admins */
02640       if(conf->gmuted) {
02641          conf->gmuted = 0;
02642          ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, &conf);
02643          if (!ast_streamfile(chan, "conf-now-unmuted", chan->language)) {
02644             ast_waitstream(chan, "");
02645          }
02646       } else {
02647          conf->gmuted = 1;
02648          ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_muted_cb, &conf);
02649          if (!ast_streamfile(chan, "conf-now-muted", chan->language)) {
02650             ast_waitstream(chan, "");
02651          }
02652       }
02653       ast_stopstream(chan);
02654       *menu_mode = MENU_DISABLED;
02655       break;
02656 
02657    case '4': /* *84 Record conference */
02658       if (conf->recording != MEETME_RECORD_ACTIVE) {
02659          ast_set_flag64(confflags, CONFFLAG_RECORDCONF);
02660          if (!conf->recordingfilename) {
02661             const char *var;
02662             ast_channel_lock(chan);
02663             if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
02664                conf->recordingfilename = ast_strdup(var);
02665             }
02666             if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
02667                conf->recordingformat = ast_strdup(var);
02668             }
02669             ast_channel_unlock(chan);
02670             if (!conf->recordingfilename) {
02671                snprintf(recordingtmp, recordingtmp_size, "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
02672                conf->recordingfilename = ast_strdup(recordingtmp);
02673             }
02674             if (!conf->recordingformat) {
02675                conf->recordingformat = ast_strdup("wav");
02676             }
02677             ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
02678             conf->confno, conf->recordingfilename, conf->recordingformat);
02679          }
02680 
02681          ast_mutex_lock(&conf->recordthreadlock);
02682          if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, chan, "pseudo", NULL)))) {
02683             ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
02684             ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
02685             dahdic->chan = 0;
02686             dahdic->confno = conf->dahdiconf;
02687             dahdic->confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
02688             if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, dahdic)) {
02689                ast_log(LOG_WARNING, "Error starting listen channel\n");
02690                ast_hangup(conf->lchan);
02691                conf->lchan = NULL;
02692             } else {
02693                ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
02694             }
02695          }
02696          ast_mutex_unlock(&conf->recordthreadlock);
02697          if (!ast_streamfile(chan, "conf-now-recording", chan->language)) {
02698             ast_waitstream(chan, "");
02699          }
02700       }
02701 
02702       ast_stopstream(chan);
02703       *menu_mode = MENU_DISABLED;
02704       break;
02705 
02706    case '8': /* *88 Exit the menu and return to the conference... without an error message */
02707       ast_stopstream(chan);
02708       *menu_mode = MENU_DISABLED;
02709       break;
02710 
02711    default:
02712       if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
02713          ast_waitstream(chan, "");
02714       }
02715       ast_stopstream(chan);
02716       *menu_mode = MENU_DISABLED;
02717       break;
02718    }
02719 }

static void meetme_menu_normal ( enum menu_modes menu_mode,
int *  dtmf,
struct ast_conference conf,
struct ast_flags64 confflags,
struct ast_channel chan,
struct ast_conf_user user 
) [static]

Definition at line 2349 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ast_streamfile(), ast_test_flag64, ast_waitstream(), CONFFLAG_MONITOR, ast_conference::confno, MENU_DISABLED, rt_extend_conf(), tweak_listen_volume(), tweak_talk_volume(), VOL_DOWN, and VOL_UP.

Referenced by meetme_menu().

02350 {
02351    switch (*dtmf) {
02352    case '1': /* Un/Mute */
02353       *menu_mode = MENU_DISABLED;
02354 
02355       /* user can only toggle the self-muted state */
02356       user->adminflags ^= ADMINFLAG_SELFMUTED;
02357 
02358       /* they can't override the admin mute state */
02359       if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02360          if (!ast_streamfile(chan, "conf-muted", chan->language)) {
02361             ast_waitstream(chan, "");
02362          }
02363       } else {
02364          if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
02365             ast_waitstream(chan, "");
02366          }
02367       }
02368       break;
02369 
02370    case '2':
02371       *menu_mode = MENU_DISABLED;
02372       if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
02373          user->adminflags |= ADMINFLAG_T_REQUEST;
02374       }
02375 
02376       if (user->adminflags & ADMINFLAG_T_REQUEST) {
02377          if (!ast_streamfile(chan, "beep", chan->language)) {
02378             ast_waitstream(chan, "");
02379          }
02380       }
02381       break;
02382 
02383    case '4':
02384       tweak_listen_volume(user, VOL_DOWN);
02385       break;
02386    case '5':
02387       /* Extend RT conference */
02388       if (rt_schedule) {
02389          rt_extend_conf(conf->confno);
02390       }
02391       *menu_mode = MENU_DISABLED;
02392       break;
02393 
02394    case '6':
02395       tweak_listen_volume(user, VOL_UP);
02396       break;
02397 
02398    case '7':
02399       tweak_talk_volume(user, VOL_DOWN);
02400       break;
02401 
02402    case '8':
02403       *menu_mode = MENU_DISABLED;
02404       break;
02405 
02406    case '9':
02407       tweak_talk_volume(user, VOL_UP);
02408       break;
02409 
02410    default:
02411       *menu_mode = MENU_DISABLED;
02412       if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
02413          ast_waitstream(chan, "");
02414       }
02415       break;
02416    }
02417 }

static char* meetme_mute_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1694 of file app_meetme.c.

References ast_cli_args::argc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_meetmecmd_mute_kick(), ast_cli_args::line, meetme_cmd_helper(), ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

01695 {
01696    switch (cmd) {
01697    case CLI_INIT:
01698       e->command = "meetme {mute|unmute}";
01699       e->usage =
01700          "Usage: meetme mute|unmute <confno> all|<userno>\n"
01701          "       Mute or unmute a conference or a user in a conference.\n";
01702       return NULL;
01703    case CLI_GENERATE:
01704       return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
01705    }
01706 
01707    if (a->argc != 4) {
01708       return CLI_SHOWUSAGE;
01709    }
01710 
01711    return meetme_cmd_helper(a);
01712 }

static char* meetme_show_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1451 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_free, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_str_buffer(), ast_str_create(), ast_str_set(), ast_test_flag64, ast_channel::caller, ast_conf_user::chan, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd_list(), CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_cli_args::fd, ast_party_caller::id, ast_conference::isdynamic, istalking(), ast_conf_user::jointime, ast_cli_args::line, ast_conference::locked, ast_conference::markedusers, MC_DATA_FORMAT, MC_HEADER_FORMAT, ast_cli_args::n, ast_party_id::name, ast_party_id::number, ast_cli_args::pos, S_COR, ast_conference::start, ast_party_name::str, ast_party_number::str, STR_CONCISE, ast_conf_user::talking, total, ast_cli_entry::usage, ast_conf_user::user_no, ast_conference::usercontainer, ast_conf_user::userflags, ast_conference::users, ast_party_name::valid, ast_party_number::valid, and ast_cli_args::word.

01452 {
01453    /* Process the command */
01454    struct ast_conf_user *user;
01455    struct ast_conference *cnf;
01456    int hr, min, sec;
01457    int total = 0;
01458    time_t now;
01459 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s  %-8s  %-6s\n"
01460 #define MC_DATA_FORMAT "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s  %-6s\n"
01461 
01462    switch (cmd) {
01463    case CLI_INIT:
01464       e->command = "meetme list";
01465       e->usage =
01466          "Usage: meetme list [<confno>] [" STR_CONCISE "]\n"
01467          "       List all conferences or a specific conference.\n";
01468       return NULL;
01469    case CLI_GENERATE:
01470       return complete_meetmecmd_list(a->line, a->word, a->pos, a->n);
01471    }
01472 
01473    if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], STR_CONCISE))) {
01474       /* List all the conferences */
01475       int concise = (a->argc == 3);
01476       struct ast_str *marked_users;
01477 
01478       if (!(marked_users = ast_str_create(30))) {
01479          return CLI_FAILURE;
01480       }
01481 
01482       now = time(NULL);
01483       AST_LIST_LOCK(&confs);
01484       if (AST_LIST_EMPTY(&confs)) {
01485          if (!concise) {
01486             ast_cli(a->fd, "No active MeetMe conferences.\n");
01487          }
01488          AST_LIST_UNLOCK(&confs);
01489          ast_free(marked_users);
01490          return CLI_SUCCESS;
01491       }
01492       if (!concise) {
01493          ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
01494       }
01495       AST_LIST_TRAVERSE(&confs, cnf, list) {
01496          hr = (now - cnf->start) / 3600;
01497          min = ((now - cnf->start) % 3600) / 60;
01498          sec = (now - cnf->start) % 60;
01499          if (!concise) {
01500             if (cnf->markedusers == 0) {
01501                ast_str_set(&marked_users, 0, "N/A ");
01502             } else {
01503                ast_str_set(&marked_users, 0, "%4.4d", cnf->markedusers);
01504             }
01505             ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users,
01506                ast_str_buffer(marked_users), hr, min, sec,
01507                cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
01508          } else {
01509             ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
01510                cnf->confno,
01511                cnf->users,
01512                cnf->markedusers,
01513                hr, min, sec,
01514                cnf->isdynamic,
01515                cnf->locked);
01516          }
01517 
01518          total += cnf->users;
01519       }
01520       AST_LIST_UNLOCK(&confs);
01521       if (!concise) {
01522          ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
01523       }
01524       ast_free(marked_users);
01525       return CLI_SUCCESS;
01526    }
01527    if (a->argc == 3 || (a->argc == 4 && !strcasecmp(a->argv[3], STR_CONCISE))) {
01528       struct ao2_iterator user_iter;
01529       int concise = (a->argc == 4);
01530 
01531       /* List all the users in a conference */
01532       if (AST_LIST_EMPTY(&confs)) {
01533          if (!concise) {
01534             ast_cli(a->fd, "No active MeetMe conferences.\n");
01535          }
01536          return CLI_SUCCESS;
01537       }
01538       /* Find the right conference */
01539       AST_LIST_LOCK(&confs);
01540       AST_LIST_TRAVERSE(&confs, cnf, list) {
01541          if (strcmp(cnf->confno, a->argv[2]) == 0) {
01542             break;
01543          }
01544       }
01545       if (!cnf) {
01546          if (!concise)
01547             ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
01548          AST_LIST_UNLOCK(&confs);
01549          return CLI_SUCCESS;
01550       }
01551       /* Show all the users */
01552       time(&now);
01553       user_iter = ao2_iterator_init(cnf->usercontainer, 0);
01554       while((user = ao2_iterator_next(&user_iter))) {
01555          hr = (now - user->jointime) / 3600;
01556          min = ((now - user->jointime) % 3600) / 60;
01557          sec = (now - user->jointime) % 60;
01558          if (!concise) {
01559             ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
01560                user->user_no,
01561                S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
01562                S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
01563                user->chan->name,
01564                ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "(Admin)" : "",
01565                ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "(Listen only)" : "",
01566                user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
01567                user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
01568                istalking(user->talking), hr, min, sec); 
01569          } else {
01570             ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
01571                user->user_no,
01572                S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, ""),
01573                S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, ""),
01574                user->chan->name,
01575                ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "1" : "",
01576                ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "1" : "",
01577                user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
01578                user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
01579                user->talking, hr, min, sec);
01580          }
01581          ao2_ref(user, -1);
01582       }
01583       ao2_iterator_destroy(&user_iter);
01584       if (!concise) {
01585          ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
01586       }
01587       AST_LIST_UNLOCK(&confs);
01588       return CLI_SUCCESS;
01589    }
01590    return CLI_SHOWUSAGE;
01591 }

static int meetmemute ( struct mansession s,
const struct message m,
int  mute 
) [static]

Definition at line 5021 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ao2_find, ao2_ref, 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, LOG_NOTICE, ast_conf_user::user_no, and ast_conference::usercontainer.

Referenced by action_meetmemute(), and action_meetmeunmute().

05022 {
05023    struct ast_conference *conf;
05024    struct ast_conf_user *user;
05025    const char *confid = astman_get_header(m, "Meetme");
05026    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
05027    int userno;
05028 
05029    if (ast_strlen_zero(confid)) {
05030       astman_send_error(s, m, "Meetme conference not specified");
05031       return 0;
05032    }
05033 
05034    if (ast_strlen_zero(userid)) {
05035       astman_send_error(s, m, "Meetme user number not specified");
05036       return 0;
05037    }
05038 
05039    userno = strtoul(userid, &userid, 10);
05040 
05041    if (*userid) {
05042       astman_send_error(s, m, "Invalid user number");
05043       return 0;
05044    }
05045 
05046    /* Look in the conference list */
05047    AST_LIST_LOCK(&confs);
05048    AST_LIST_TRAVERSE(&confs, conf, list) {
05049       if (!strcmp(confid, conf->confno))
05050          break;
05051    }
05052 
05053    if (!conf) {
05054       AST_LIST_UNLOCK(&confs);
05055       astman_send_error(s, m, "Meetme conference does not exist");
05056       return 0;
05057    }
05058 
05059    user = ao2_find(conf->usercontainer, &userno, 0);
05060 
05061    if (!user) {
05062       AST_LIST_UNLOCK(&confs);
05063       astman_send_error(s, m, "User number not found");
05064       return 0;
05065    }
05066 
05067    if (mute)
05068       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
05069    else
05070       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
05071 
05072    AST_LIST_UNLOCK(&confs);
05073 
05074    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);
05075 
05076    ao2_ref(user, -1);
05077    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
05078    return 0;
05079 }

static enum ast_device_state meetmestate ( const char *  data  )  [static]

Callback for devicestate providers.

Definition at line 5260 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, and ast_conference::users.

Referenced by load_module().

05261 {
05262    struct ast_conference *conf;
05263 
05264    /* Find conference */
05265    AST_LIST_LOCK(&confs);
05266    AST_LIST_TRAVERSE(&confs, conf, list) {
05267       if (!strcmp(data, conf->confno))
05268          break;
05269    }
05270    AST_LIST_UNLOCK(&confs);
05271    if (!conf)
05272       return AST_DEVICE_INVALID;
05273 
05274 
05275    /* SKREP to fill */
05276    if (!conf->users)
05277       return AST_DEVICE_NOT_INUSE;
05278 
05279    return AST_DEVICE_INUSE;
05280 }

static struct sla_ringing_trunk* queue_ringing_trunk ( struct sla_trunk trunk  )  [static, read]

Definition at line 6691 of file app_meetme.c.

References ALL_TRUNK_REFS, ao2_ref, ast_calloc, AST_LIST_INSERT_HEAD, ast_mutex_lock, ast_mutex_unlock, ast_tvnow(), sla_ringing_trunk::ring_begin, sla, sla_change_trunk_state(), SLA_EVENT_RINGING_TRUNK, sla_queue_event(), SLA_TRUNK_STATE_RINGING, and sla_ringing_trunk::trunk.

Referenced by sla_trunk_exec().

06692 {
06693    struct sla_ringing_trunk *ringing_trunk;
06694 
06695    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk)))) {
06696       return NULL;
06697    }
06698 
06699    ao2_ref(trunk, 1);
06700    ringing_trunk->trunk = trunk;
06701    ringing_trunk->ring_begin = ast_tvnow();
06702 
06703    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
06704 
06705    ast_mutex_lock(&sla.lock);
06706    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
06707    ast_mutex_unlock(&sla.lock);
06708 
06709    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06710 
06711    return ringing_trunk;
06712 }

static void * recordthread ( void *  args  )  [static]

Definition at line 5191 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_strlen_zero(), ast_waitfor(), ast_writefile(), ast_writestream(), f, filename_parse(), ast_frame::flags, ast_frame::frametype, ast_conference::lchan, ast_conference::listenlock, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, ast_conference::origframe, ast_conference::recordingfilename, ast_conference::recordingformat, and ast_conference::transframe.

05192 {
05193    struct ast_conference *cnf = args;
05194    struct ast_frame *f = NULL;
05195    int flags;
05196    struct ast_filestream *s = NULL;
05197    int res = 0;
05198    int x;
05199    const char *oldrecordingfilename = NULL;
05200    char filename_buffer[PATH_MAX];
05201 
05202    if (!cnf || !cnf->lchan) {
05203       pthread_exit(0);
05204    }
05205 
05206    filename_buffer[0] = '\0';
05207    filename_parse(cnf->recordingfilename, filename_buffer);
05208 
05209    ast_stopstream(cnf->lchan);
05210    flags = O_CREAT | O_TRUNC | O_WRONLY;
05211 
05212 
05213    cnf->recording = MEETME_RECORD_ACTIVE;
05214    while (ast_waitfor(cnf->lchan, -1) > -1) {
05215       if (cnf->recording == MEETME_RECORD_TERMINATE) {
05216          AST_LIST_LOCK(&confs);
05217          AST_LIST_UNLOCK(&confs);
05218          break;
05219       }
05220       if (!s && !(ast_strlen_zero(filename_buffer)) && (filename_buffer != oldrecordingfilename)) {
05221          s = ast_writefile(filename_buffer, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
05222          oldrecordingfilename = filename_buffer;
05223       }
05224       
05225       f = ast_read(cnf->lchan);
05226       if (!f) {
05227          res = -1;
05228          break;
05229       }
05230       if (f->frametype == AST_FRAME_VOICE) {
05231          ast_mutex_lock(&cnf->listenlock);
05232          for (x = 0; x < AST_FRAME_BITS; x++) {
05233             /* Free any translations that have occured */
05234             if (cnf->transframe[x]) {
05235                ast_frfree(cnf->transframe[x]);
05236                cnf->transframe[x] = NULL;
05237             }
05238          }
05239          if (cnf->origframe)
05240             ast_frfree(cnf->origframe);
05241          cnf->origframe = ast_frdup(f);
05242          ast_mutex_unlock(&cnf->listenlock);
05243          if (s)
05244             res = ast_writestream(s, f);
05245          if (res) {
05246             ast_frfree(f);
05247             break;
05248          }
05249       }
05250       ast_frfree(f);
05251    }
05252    cnf->recording = MEETME_RECORD_OFF;
05253    if (s)
05254       ast_closestream(s);
05255    
05256    pthread_exit(0);
05257 }

static int reload ( void   )  [static]

Definition at line 7767 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

07768 {
07769    ast_unload_realtime("meetme");
07770    return load_config(1);
07771 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 1126 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_RXGAIN, AST_OPTION_TXGAIN, and ast_conf_user::chan.

Referenced by admin_exec(), conf_run(), and user_reset_vol_cb().

01127 {
01128    signed char zero_volume = 0;
01129 
01130    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
01131    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
01132 }

static int rt_extend_conf ( const char *  confno  )  [static]

Definition at line 2116 of file app_meetme.c.

References ast_copy_string(), ast_debug, ast_load_realtime(), ast_localtime(), ast_mktime(), ast_strftime(), ast_strptime(), ast_tvnow(), ast_update_realtime(), ast_variables_destroy(), ast_conference::bookid, DATE_FORMAT, ast_conference::endtime, ast_variable::name, ast_variable::next, ast_variable::value, and var.

Referenced by admin_exec(), meetme_menu_admin(), and meetme_menu_normal().

02117 {
02118    char currenttime[32];
02119    char endtime[32];
02120    struct timeval now;
02121    struct ast_tm tm;
02122    struct ast_variable *var, *orig_var;
02123    char bookid[51];
02124 
02125    if (!extendby) {
02126       return 0;
02127    }
02128 
02129    now = ast_tvnow();
02130 
02131    ast_localtime(&now, &tm, NULL);
02132    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02133 
02134    var = ast_load_realtime("meetme", "confno",
02135       confno, "startTime<= ", currenttime,
02136       "endtime>= ", currenttime, NULL);
02137 
02138    orig_var = var;
02139 
02140    /* Identify the specific RealTime conference */
02141    while (var) {
02142       if (!strcasecmp(var->name, "bookid")) {
02143          ast_copy_string(bookid, var->value, sizeof(bookid));
02144       }
02145       if (!strcasecmp(var->name, "endtime")) {
02146          ast_copy_string(endtime, var->value, sizeof(endtime));
02147       }
02148 
02149       var = var->next;
02150    }
02151    ast_variables_destroy(orig_var);
02152 
02153    ast_strptime(endtime, DATE_FORMAT, &tm);
02154    now = ast_mktime(&tm, NULL);
02155 
02156    now.tv_sec += extendby;
02157 
02158    ast_localtime(&now, &tm, NULL);
02159    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02160    strcat(currenttime, "0"); /* Seconds needs to be 00 */
02161 
02162    var = ast_load_realtime("meetme", "confno",
02163       confno, "startTime<= ", currenttime,
02164       "endtime>= ", currenttime, NULL);
02165 
02166    /* If there is no conflict with extending the conference, update the DB */
02167    if (!var) {
02168       ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
02169       ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
02170       return 0;
02171 
02172    }
02173 
02174    ast_variables_destroy(var);
02175    return -1;
02176 }

static void* run_station ( void *  data  )  [static]

Definition at line 5577 of file app_meetme.c.

References admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), args, ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_cond_signal, ast_dial_destroy(), ast_dial_join(), ast_free, ast_mutex_lock, ast_mutex_unlock, ast_set_flag64, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), build_conf(), run_station_args::cond, run_station_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dispose_conf(), RAII_VAR, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, run_station_args::station, and run_station_args::trunk_ref.

Referenced by sla_handle_dial_state_event().

05578 {
05579    RAII_VAR(struct sla_station *, station, NULL, unref_obj);
05580    RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, unref_obj);
05581    struct ast_str *conf_name = ast_str_create(16);
05582    struct ast_flags64 conf_flags = { 0 };
05583    struct ast_conference *conf;
05584 
05585    {
05586       struct run_station_args *args = data;
05587       station = args->station;
05588       trunk_ref = args->trunk_ref;
05589       ast_mutex_lock(args->cond_lock);
05590       ast_cond_signal(args->cond);
05591       ast_mutex_unlock(args->cond_lock);
05592       /* args is no longer valid here. */
05593    }
05594 
05595    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
05596    ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
05597    ast_set_flag64(&conf_flags, 
05598       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05599    answer_trunk_chan(trunk_ref->chan);
05600    conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan, NULL);
05601    if (conf) {
05602       conf_run(trunk_ref->chan, conf, &conf_flags, NULL);
05603       dispose_conf(conf);
05604       conf = NULL;
05605    }
05606    trunk_ref->chan = NULL;
05607    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05608       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05609       ast_str_append(&conf_name, 0, ",K");
05610       admin_exec(NULL, ast_str_buffer(conf_name));
05611       trunk_ref->trunk->hold_stations = 0;
05612       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05613    }
05614 
05615    ast_dial_join(station->dial);
05616    ast_dial_destroy(station->dial);
05617    station->dial = NULL;
05618    ast_free(conf_name);
05619 
05620    return NULL;
05621 }

static void send_talking_event ( struct ast_channel chan,
struct ast_conference conf,
struct ast_conf_user user,
int  talking 
) [static]

Definition at line 2270 of file app_meetme.c.

References ast_manager_event, ast_conference::confno, EVENT_FLAG_CALL, and ast_conf_user::user_no.

Referenced by set_user_talking().

02271 {
02272    ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking",
02273       "Channel: %s\r\n"
02274       "Uniqueid: %s\r\n"
02275       "Meetme: %s\r\n"
02276       "Usernum: %d\r\n"
02277       "Status: %s\r\n",
02278       chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
02279 }

static int set_listen_volume ( struct ast_conf_user user,
int  volume 
) [static]

Definition at line 1055 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_TXGAIN, and ast_conf_user::chan.

Referenced by tweak_listen_volume().

01056 {
01057    char gain_adjust;
01058 
01059    /* attempt to make the adjustment in the channel driver;
01060       if successful, don't adjust in the frame reading routine
01061    */
01062    gain_adjust = gain_map[volume + 5];
01063 
01064    return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
01065 }

static int set_talk_volume ( struct ast_conf_user user,
int  volume 
) [static]

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

01044 {
01045    char gain_adjust;
01046 
01047    /* attempt to make the adjustment in the channel driver;
01048       if successful, don't adjust in the frame reading routine
01049    */
01050    gain_adjust = gain_map[volume + 5];
01051 
01052    return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
01053 }

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 2281 of file app_meetme.c.

References send_talking_event(), and ast_conf_user::talking.

Referenced by conf_run().

02282 {
02283    int last_talking = user->talking;
02284    if (last_talking == talking)
02285       return;
02286 
02287    user->talking = talking;
02288 
02289    if (monitor) {
02290       /* Check if talking state changed. Take care of -1 which means unmonitored */
02291       int was_talking = (last_talking > 0);
02292       int now_talking = (talking > 0);
02293       if (was_talking != now_talking) {
02294          send_talking_event(chan, conf, user, now_talking);
02295       }
02296    }
02297 }

static void sla_add_trunk_to_station ( struct sla_station station,
struct ast_variable var 
) [static]

Definition at line 7086 of file app_meetme.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_atomic_fetchadd_int(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_strdupa, create_trunk_ref(), LOG_ERROR, LOG_WARNING, name, RAII_VAR, sla_create_station_ref(), sla_find_trunk(), SLA_TRUNK_STATE_IDLE, value, and ast_variable::value.

Referenced by sla_build_station().

07087 {
07088    RAII_VAR(struct sla_trunk *, trunk, NULL, unref_obj);
07089    struct sla_trunk_ref *trunk_ref = NULL;
07090    struct sla_station_ref *station_ref;
07091    char *trunk_name, *options, *cur;
07092    int existing_trunk_ref = 0;
07093    int existing_station_ref = 0;
07094 
07095    options = ast_strdupa(var->value);
07096    trunk_name = strsep(&options, ",");
07097 
07098    trunk = sla_find_trunk(trunk_name);
07099    if (!trunk) {
07100       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
07101       return;
07102    }
07103 
07104    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
07105       if (trunk_ref->trunk == trunk) {
07106          trunk_ref->mark = 0;
07107          existing_trunk_ref = 1;
07108          break;
07109       }
07110    }
07111 
07112    if (!trunk_ref && !(trunk_ref = create_trunk_ref(trunk))) {
07113       return;
07114    }
07115 
07116    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
07117 
07118    while ((cur = strsep(&options, ","))) {
07119       char *name, *value = cur;
07120       name = strsep(&value, "=");
07121       if (!strcasecmp(name, "ringtimeout")) {
07122          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
07123             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
07124                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
07125             trunk_ref->ring_timeout = 0;
07126          }
07127       } else if (!strcasecmp(name, "ringdelay")) {
07128          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
07129             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
07130                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
07131             trunk_ref->ring_delay = 0;
07132          }
07133       } else {
07134          ast_log(LOG_WARNING, "Invalid option '%s' for "
07135             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
07136       }
07137    }
07138 
07139    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
07140       if (station_ref->station == station) {
07141          station_ref->mark = 0;
07142          existing_station_ref = 1;
07143          break;
07144       }
07145    }
07146 
07147    if (!station_ref && !(station_ref = sla_create_station_ref(station))) {
07148       if (!existing_trunk_ref) {
07149          ao2_ref(trunk_ref, -1);
07150       } else {
07151          trunk_ref->mark = 1;
07152       }
07153       return;
07154    }
07155 
07156    if (!existing_station_ref) {
07157       ao2_lock(trunk);
07158       AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
07159       ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
07160       ao2_unlock(trunk);
07161    }
07162 
07163    if (!existing_trunk_ref) {
07164       ao2_lock(station);
07165       AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
07166       ao2_unlock(station);
07167    }
07168 }

static int sla_build_station ( struct ast_config cfg,
const char *  cat 
) [static]

Definition at line 7170 of file app_meetme.c.

References ao2_alloc, ao2_link, ao2_lock, ao2_unlock, ast_add_extension2(), ast_context_find_or_create(), ast_free_ptr(), AST_LIST_TRAVERSE, ast_log(), AST_MAX_APP, AST_MAX_EXTENSION, ast_strdup, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), context, exten, ast_variable::lineno, LOG_ERROR, LOG_WARNING, ast_variable::name, name, ast_variable::next, PRIORITY_HINT, RAII_VAR, sla_add_trunk_to_station(), SLA_CONFIG_FILE, sla_find_station(), SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, sla_station_destructor(), sla_stations, ast_variable::value, and var.

Referenced by sla_load_config().

07171 {
07172    RAII_VAR(struct sla_station *, station, NULL, unref_obj);
07173    struct ast_variable *var;
07174    const char *dev;
07175    int existing_station = 0;
07176 
07177    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
07178       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
07179       return -1;
07180    }
07181 
07182    if ((station = sla_find_station(cat))) {
07183       station->mark = 0;
07184       existing_station = 1;
07185    } else if ((station = ao2_alloc(sizeof(*station), sla_station_destructor))) {
07186       if (ast_string_field_init(station, 32)) {
07187          return -1;
07188       }
07189       ast_string_field_set(station, name, cat);
07190    } else {
07191       return -1;
07192    }
07193 
07194    ao2_lock(station);
07195 
07196    ast_string_field_set(station, device, dev);
07197 
07198    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
07199       if (!strcasecmp(var->name, "trunk")) {
07200          ao2_unlock(station);
07201          sla_add_trunk_to_station(station, var);
07202          ao2_lock(station);
07203       } else if (!strcasecmp(var->name, "autocontext")) {
07204          ast_string_field_set(station, autocontext, var->value);
07205       } else if (!strcasecmp(var->name, "ringtimeout")) {
07206          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
07207             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
07208                var->value, station->name);
07209             station->ring_timeout = 0;
07210          }
07211       } else if (!strcasecmp(var->name, "ringdelay")) {
07212          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
07213             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
07214                var->value, station->name);
07215             station->ring_delay = 0;
07216          }
07217       } else if (!strcasecmp(var->name, "hold")) {
07218          if (!strcasecmp(var->value, "private"))
07219             station->hold_access = SLA_HOLD_PRIVATE;
07220          else if (!strcasecmp(var->value, "open"))
07221             station->hold_access = SLA_HOLD_OPEN;
07222          else {
07223             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
07224                var->value, station->name);
07225          }
07226 
07227       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
07228          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
07229             var->name, var->lineno, SLA_CONFIG_FILE);
07230       }
07231    }
07232 
07233    ao2_unlock(station);
07234 
07235    if (!ast_strlen_zero(station->autocontext)) {
07236       struct ast_context *context;
07237       struct sla_trunk_ref *trunk_ref;
07238       context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
07239       if (!context) {
07240          ast_log(LOG_ERROR, "Failed to automatically find or create "
07241             "context '%s' for SLA!\n", station->autocontext);
07242          return -1;
07243       }
07244       /* The extension for when the handset goes off-hook.
07245        * exten => station1,1,SLAStation(station1) */
07246       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
07247          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
07248          ast_log(LOG_ERROR, "Failed to automatically create extension "
07249             "for trunk '%s'!\n", station->name);
07250          return -1;
07251       }
07252       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
07253          char exten[AST_MAX_EXTENSION];
07254          char hint[AST_MAX_APP];
07255          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
07256          snprintf(hint, sizeof(hint), "SLA:%s", exten);
07257          /* Extension for this line button 
07258           * exten => station1_line1,1,SLAStation(station1_line1) */
07259          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
07260             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
07261             ast_log(LOG_ERROR, "Failed to automatically create extension "
07262                "for trunk '%s'!\n", station->name);
07263             return -1;
07264          }
07265          /* Hint for this line button 
07266           * exten => station1_line1,hint,SLA:station1_line1 */
07267          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
07268             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
07269             ast_log(LOG_ERROR, "Failed to automatically create hint "
07270                "for trunk '%s'!\n", station->name);
07271             return -1;
07272          }
07273       }
07274    }
07275 
07276    if (!existing_station) {
07277       ao2_link(sla_stations, station);
07278    }
07279 
07280    return 0;
07281 }

static int sla_build_trunk ( struct ast_config cfg,
const char *  cat 
) [static]

Definition at line 6997 of file app_meetme.c.

References ao2_alloc, ao2_link, ao2_lock, ao2_unlock, ast_add_extension2(), ast_context_find_or_create(), ast_false(), ast_free_ptr(), ast_log(), ast_strdup, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), context, ast_variable::lineno, LOG_ERROR, LOG_WARNING, ast_variable::name, name, ast_variable::next, RAII_VAR, sla_check_device(), SLA_CONFIG_FILE, sla_find_trunk(), SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, sla_trunk_destructor(), sla_trunks, ast_variable::value, and var.

Referenced by sla_load_config().

06998 {
06999    RAII_VAR(struct sla_trunk *, trunk, NULL, unref_obj);
07000    struct ast_variable *var;
07001    const char *dev;
07002    int existing_trunk = 0;
07003 
07004    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
07005       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
07006       return -1;
07007    }
07008 
07009    if (sla_check_device(dev)) {
07010       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with invalid device '%s'!\n",
07011          cat, dev);
07012       return -1;
07013    }
07014 
07015    if ((trunk = sla_find_trunk(cat))) {
07016       trunk->mark = 0;
07017       existing_trunk = 1;
07018    } else if ((trunk = ao2_alloc(sizeof(*trunk), sla_trunk_destructor))) {
07019       if (ast_string_field_init(trunk, 32)) {
07020          return -1;
07021       }
07022       ast_string_field_set(trunk, name, cat);
07023    } else {
07024       return -1;
07025    }
07026 
07027    ao2_lock(trunk);
07028 
07029    ast_string_field_set(trunk, device, dev);
07030 
07031    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
07032       if (!strcasecmp(var->name, "autocontext"))
07033          ast_string_field_set(trunk, autocontext, var->value);
07034       else if (!strcasecmp(var->name, "ringtimeout")) {
07035          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
07036             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
07037                var->value, trunk->name);
07038             trunk->ring_timeout = 0;
07039          }
07040       } else if (!strcasecmp(var->name, "barge"))
07041          trunk->barge_disabled = ast_false(var->value);
07042       else if (!strcasecmp(var->name, "hold")) {
07043          if (!strcasecmp(var->value, "private"))
07044             trunk->hold_access = SLA_HOLD_PRIVATE;
07045          else if (!strcasecmp(var->value, "open"))
07046             trunk->hold_access = SLA_HOLD_OPEN;
07047          else {
07048             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
07049                var->value, trunk->name);
07050          }
07051       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
07052          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
07053             var->name, var->lineno, SLA_CONFIG_FILE);
07054       }
07055    }
07056 
07057    ao2_unlock(trunk);
07058 
07059    if (!ast_strlen_zero(trunk->autocontext)) {
07060       struct ast_context *context;
07061       context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
07062       if (!context) {
07063          ast_log(LOG_ERROR, "Failed to automatically find or create "
07064             "context '%s' for SLA!\n", trunk->autocontext);
07065          return -1;
07066       }
07067       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
07068          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
07069          ast_log(LOG_ERROR, "Failed to automatically create extension "
07070             "for trunk '%s'!\n", trunk->name);
07071          return -1;
07072       }
07073    }
07074 
07075    if (!existing_trunk) {
07076       ao2_link(sla_trunks, trunk);
07077    }
07078 
07079    return 0;
07080 }

static int sla_calc_station_delays ( unsigned int *  timeout  )  [static]

Calculate the ring delay for a station.

Note:
Assumes sla.lock is locked

Definition at line 6205 of file app_meetme.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), sla_choose_ringing_trunk(), and sla_stations.

Referenced by sla_process_timers().

06206 {
06207    struct sla_station *station;
06208    int res = 0;
06209    struct ao2_iterator i;
06210 
06211    i = ao2_iterator_init(sla_stations, 0);
06212    for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
06213       struct sla_ringing_trunk *ringing_trunk;
06214       int time_left;
06215 
06216       /* Ignore stations already ringing */
06217       if (sla_check_ringing_station(station))
06218          continue;
06219 
06220       /* Ignore stations already on a call */
06221       if (sla_check_inuse_station(station))
06222          continue;
06223 
06224       /* Ignore stations that don't have one of their trunks ringing */
06225       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
06226          continue;
06227 
06228       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
06229          continue;
06230 
06231       /* If there is no time left, then the station needs to start ringing.
06232        * Return non-zero so that an event will be queued up an event to 
06233        * make that happen. */
06234       if (time_left <= 0) {
06235          res = 1;
06236          continue;
06237       }
06238 
06239       if (time_left < *timeout)
06240          *timeout = time_left;
06241    }
06242    ao2_iterator_destroy(&i);
06243 
06244    return res;
06245 }

static int sla_calc_station_timeouts ( unsigned int *  timeout  )  [static]

Process station ring timeouts.

Note:
Called with sla.lock locked
Returns:
non-zero if a change to the ringing stations was made

Definition at line 6122 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, SLA_STATION_HANGUP_TIMEOUT, sla_stop_ringing_station(), sla_ringing_station::station, and sla_ringing_trunk::trunk.

Referenced by sla_process_timers().

06123 {
06124    struct sla_ringing_trunk *ringing_trunk;
06125    struct sla_ringing_station *ringing_station;
06126    int res = 0;
06127 
06128    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
06129       unsigned int ring_timeout = 0;
06130       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
06131       struct sla_trunk_ref *trunk_ref;
06132 
06133       /* If there are any ring timeouts specified for a specific trunk
06134        * on the station, then use the highest per-trunk ring timeout.
06135        * Otherwise, use the ring timeout set for the entire station. */
06136       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
06137          struct sla_station_ref *station_ref;
06138          int trunk_time_elapsed, trunk_time_left;
06139 
06140          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
06141             if (ringing_trunk->trunk == trunk_ref->trunk)
06142                break;
06143          }
06144          if (!ringing_trunk)
06145             continue;
06146 
06147          /* If there is a trunk that is ringing without a timeout, then the
06148           * only timeout that could matter is a global station ring timeout. */
06149          if (!trunk_ref->ring_timeout)
06150             break;
06151 
06152          /* This trunk on this station is ringing and has a timeout.
06153           * However, make sure this trunk isn't still ringing from a
06154           * previous timeout.  If so, don't consider it. */
06155          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
06156             if (station_ref->station == ringing_station->station)
06157                break;
06158          }
06159          if (station_ref)
06160             continue;
06161 
06162          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
06163          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
06164          if (trunk_time_left > final_trunk_time_left)
06165             final_trunk_time_left = trunk_time_left;
06166       }
06167 
06168       /* No timeout was found for ringing trunks, and no timeout for the entire station */
06169       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
06170          continue;
06171 
06172       /* Compute how much time is left for a global station timeout */
06173       if (ringing_station->station->ring_timeout) {
06174          ring_timeout = ringing_station->station->ring_timeout;
06175          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
06176          time_left = (ring_timeout * 1000) - time_elapsed;
06177       }
06178 
06179       /* If the time left based on the per-trunk timeouts is smaller than the
06180        * global station ring timeout, use that. */
06181       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
06182          time_left = final_trunk_time_left;
06183 
06184       /* If there is no time left, the station needs to stop ringing */
06185       if (time_left <= 0) {
06186          AST_LIST_REMOVE_CURRENT(entry);
06187          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
06188          res = 1;
06189          continue;
06190       }
06191 
06192       /* There is still some time left for this station to ring, so save that
06193        * timeout if it is the first event scheduled to occur */
06194       if (time_left < *timeout)
06195          *timeout = time_left;
06196    }
06197    AST_LIST_TRAVERSE_SAFE_END;
06198 
06199    return res;
06200 }

static int sla_calc_trunk_timeouts ( unsigned int *  timeout  )  [static]

Process trunk ring timeouts.

Note:
Called with sla.lock locked
Returns:
non-zero if a change to the ringing trunks was made

Definition at line 6092 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(), pbx_builtin_setvar_helper(), sla_ringing_trunk::ring_begin, sla, sla_stop_ringing_trunk(), and sla_ringing_trunk::trunk.

Referenced by sla_process_timers().

06093 {
06094    struct sla_ringing_trunk *ringing_trunk;
06095    int res = 0;
06096 
06097    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
06098       int time_left, time_elapsed;
06099       if (!ringing_trunk->trunk->ring_timeout)
06100          continue;
06101       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
06102       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
06103       if (time_left <= 0) {
06104          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
06105          AST_LIST_REMOVE_CURRENT(entry);
06106          sla_stop_ringing_trunk(ringing_trunk);
06107          res = 1;
06108          continue;
06109       }
06110       if (time_left < *timeout)
06111          *timeout = time_left;
06112    }
06113    AST_LIST_TRAVERSE_SAFE_END;
06114 
06115    return res;
06116 }

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 5538 of file app_meetme.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), AST_LIST_TRAVERSE, sla_state_to_devstate(), and sla_stations.

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

05540 {
05541    struct sla_station *station;
05542    struct sla_trunk_ref *trunk_ref;
05543    struct ao2_iterator i;
05544 
05545    i = ao2_iterator_init(sla_stations, 0);
05546    while ((station = ao2_iterator_next(&i))) {
05547       ao2_lock(station);
05548       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05549          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
05550                || trunk_ref == exclude) {
05551             continue;
05552          }
05553          trunk_ref->state = state;
05554          ast_devstate_changed(sla_state_to_devstate(state), AST_DEVSTATE_CACHABLE,
05555                     "SLA:%s_%s", station->name, trunk->name);
05556          break;
05557       }
05558       ao2_unlock(station);
05559       ao2_ref(station, -1);
05560    }
05561    ao2_iterator_destroy(&i);
05562 }

static int sla_check_device ( const char *  device  )  [static]

Definition at line 6969 of file app_meetme.c.

References ast_strdupa, and ast_strlen_zero().

Referenced by sla_build_trunk().

06970 {
06971    char *tech, *tech_data;
06972 
06973    tech_data = ast_strdupa(device);
06974    tech = strsep(&tech_data, "/");
06975 
06976    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
06977       return -1;
06978 
06979    return 0;
06980 }

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.

Note:
assumes sla.lock is locked

Definition at line 5841 of file app_meetme.c.

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_failed_station::last_try, sla, sla_failed_station_destroy(), and sla_failed_station::station.

Referenced by sla_ring_stations().

05842 {
05843    struct sla_failed_station *failed_station;
05844    int res = 0;
05845 
05846    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
05847       if (station != failed_station->station)
05848          continue;
05849       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
05850          AST_LIST_REMOVE_CURRENT(entry);
05851          sla_failed_station_destroy(failed_station);
05852          break;
05853       }
05854       res = 1;
05855    }
05856    AST_LIST_TRAVERSE_SAFE_END
05857 
05858    return res;
05859 }

static int sla_check_inuse_station ( const struct sla_station station  )  [static]

Check to see if a station is in use.

Definition at line 5924 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

05925 {
05926    struct sla_trunk_ref *trunk_ref;
05927 
05928    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05929       if (trunk_ref->chan)
05930          return 1;
05931    }
05932 
05933    return 0;
05934 }

static int sla_check_ringing_station ( const struct sla_station station  )  [static]

Check to see if this station is already ringing.

Note:
Assumes sla.lock is locked

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

05827 {
05828    struct sla_ringing_station *ringing_station;
05829 
05830    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
05831       if (station == ringing_station->station)
05832          return 1;
05833    }
05834 
05835    return 0;
05836 }

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.

Parameters:
station the station
ringing_trunk the trunk. If NULL, the highest priority ringing trunk will be used
Returns:
the number of ms left before the delay is complete, or INT_MAX if there is no delay

Definition at line 5956 of file app_meetme.c.

References ast_tvdiff_ms(), ast_tvnow(), RAII_VAR, sla_ringing_trunk::ring_begin, sla_choose_ringing_trunk(), sla_find_trunk_ref(), and sla_ringing_trunk::trunk.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

05958 {
05959    RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, unref_obj);
05960    unsigned int delay = UINT_MAX;
05961    int time_left, time_elapsed;
05962 
05963    if (!ringing_trunk)
05964       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
05965    else
05966       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
05967 
05968    if (!ringing_trunk || !trunk_ref)
05969       return delay;
05970 
05971    /* If this station has a ring delay specific to the highest priority
05972     * ringing trunk, use that.  Otherwise, use the ring delay specified
05973     * globally for the station. */
05974    delay = trunk_ref->ring_delay;
05975    if (!delay)
05976       delay = station->ring_delay;
05977    if (!delay)
05978       return INT_MAX;
05979 
05980    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05981    time_left = (delay * 1000) - time_elapsed;
05982 
05983    return time_left;
05984 }

static int sla_check_station_hold_access ( const struct sla_trunk trunk,
const struct sla_station station 
) [static]

Definition at line 5389 of file app_meetme.c.

References AST_LIST_TRAVERSE, SLA_HOLD_PRIVATE, and SLA_TRUNK_STATE_ONHOLD_BYME.

Referenced by sla_find_trunk_ref_byname().

05391 {
05392    struct sla_station_ref *station_ref;
05393    struct sla_trunk_ref *trunk_ref;
05394 
05395    /* For each station that has this call on hold, check for private hold. */
05396    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
05397       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
05398          if (trunk_ref->trunk != trunk || station_ref->station == station)
05399             continue;
05400          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
05401             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
05402             return 1;
05403          return 0;
05404       }
05405    }
05406 
05407    return 0;
05408 }

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.

Note:
Assumes sla.lock is locked

Definition at line 5684 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

05686 {
05687    struct sla_station_ref *timed_out_station;
05688 
05689    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
05690       if (station == timed_out_station->station)
05691          return 1;
05692    }
05693 
05694    return 0;
05695 }

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.

Precondition:
sla_station is locked

Definition at line 6501 of file app_meetme.c.

References ao2_ref, AST_LIST_TRAVERSE, and SLA_TRUNK_STATE_IDLE.

Referenced by sla_station_exec().

06502 {
06503    struct sla_trunk_ref *trunk_ref = NULL;
06504 
06505    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06506       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE) {
06507          ao2_ref(trunk_ref, 1);
06508          break;
06509       }
06510    }
06511 
06512    return trunk_ref;
06513 }

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.

Parameters:
station the station
rm remove the ringing trunk once selected
trunk_ref a place to store the pointer to this stations reference to the selected trunk
Returns:
a pointer to the selected ringing trunk, or NULL if none found
Note:
Assumes that sla.lock is locked

Definition at line 5705 of file app_meetme.c.

References ao2_ref, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, sla, sla_check_timed_out_station(), and sla_ringing_trunk::trunk.

Referenced by sla_calc_station_delays(), sla_check_station_delay(), and sla_handle_dial_state_event().

05707 {
05708    struct sla_trunk_ref *s_trunk_ref;
05709    struct sla_ringing_trunk *ringing_trunk = NULL;
05710 
05711    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
05712       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05713          /* Make sure this is the trunk we're looking for */
05714          if (s_trunk_ref->trunk != ringing_trunk->trunk)
05715             continue;
05716 
05717          /* This trunk on the station is ringing.  But, make sure this station
05718           * didn't already time out while this trunk was ringing. */
05719          if (sla_check_timed_out_station(ringing_trunk, station))
05720             continue;
05721 
05722          if (rm)
05723             AST_LIST_REMOVE_CURRENT(entry);
05724 
05725          if (trunk_ref) {
05726             ao2_ref(s_trunk_ref, 1);
05727             *trunk_ref = s_trunk_ref;
05728          }
05729 
05730          break;
05731       }
05732       AST_LIST_TRAVERSE_SAFE_END;
05733    
05734       if (ringing_trunk)
05735          break;
05736    }
05737 
05738    return ringing_trunk;
05739 }

static struct sla_failed_station* sla_create_failed_station ( struct sla_station station  )  [static, read]

Definition at line 5496 of file app_meetme.c.

References ao2_ref, ast_calloc, ast_tvnow(), sla_failed_station::last_try, and sla_failed_station::station.

Referenced by sla_ring_station().

05497 {
05498    struct sla_failed_station *failed_station;
05499 
05500    if (!(failed_station = ast_calloc(1, sizeof(*failed_station)))) {
05501       return NULL;
05502    }
05503 
05504    ao2_ref(station, 1);
05505    failed_station->station = station;
05506    failed_station->last_try = ast_tvnow();
05507 
05508    return failed_station;
05509 }

static struct sla_ringing_station* sla_create_ringing_station ( struct sla_station station  )  [static, read]

Definition at line 5472 of file app_meetme.c.

References ao2_ref, ast_calloc, ast_tvnow(), sla_ringing_station::ring_begin, and sla_ringing_station::station.

Referenced by sla_ring_station().

05473 {
05474    struct sla_ringing_station *ringing_station;
05475 
05476    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
05477       return NULL;
05478 
05479    ao2_ref(station, 1);
05480    ringing_station->station = station;
05481    ringing_station->ring_begin = ast_tvnow();
05482 
05483    return ringing_station;
05484 }

static struct sla_station_ref* sla_create_station_ref ( struct sla_station station  )  [static, read]

Definition at line 5458 of file app_meetme.c.

References ao2_alloc, ao2_ref, and sla_station_ref_destructor().

Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().

05459 {
05460    struct sla_station_ref *station_ref;
05461 
05462    if (!(station_ref = ao2_alloc(sizeof(*station_ref), sla_station_ref_destructor))) {
05463       return NULL;
05464    }
05465 
05466    ao2_ref(station, 1);
05467    station_ref->station = station;
05468 
05469    return station_ref;
05470 }

static void sla_destroy ( void   )  [static]

Definition at line 6943 of file app_meetme.c.

References ao2_callback, ao2_ref, ast_cond_destroy, ast_cond_signal, ast_context_destroy(), ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, sla, sla_registrar, sla_station_release_refs(), sla_stations, sla_trunk_release_refs(), and sla_trunks.

Referenced by unload_module().

06944 {
06945    if (sla.thread != AST_PTHREADT_NULL) {
06946       ast_mutex_lock(&sla.lock);
06947       sla.stop = 1;
06948       ast_cond_signal(&sla.cond);
06949       ast_mutex_unlock(&sla.lock);
06950       pthread_join(sla.thread, NULL);
06951    }
06952 
06953    /* Drop any created contexts from the dialplan */
06954    ast_context_destroy(NULL, sla_registrar);
06955 
06956    ast_mutex_destroy(&sla.lock);
06957    ast_cond_destroy(&sla.cond);
06958 
06959    ao2_callback(sla_trunks, 0, sla_trunk_release_refs, NULL);
06960    ao2_callback(sla_stations, 0, sla_station_release_refs, NULL);
06961 
06962    ao2_ref(sla_trunks, -1);
06963    sla_trunks = NULL;
06964 
06965    ao2_ref(sla_stations, -1);
06966    sla_stations = NULL;
06967 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 5676 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

05677 {
05678    sla_queue_event(SLA_EVENT_DIAL_STATE);
05679 }

static void sla_event_destroy ( struct sla_event event  )  [static]

Definition at line 6284 of file app_meetme.c.

References ao2_ref, ast_free, sla_event::station, and sla_event::trunk_ref.

Referenced by sla_thread().

06285 {
06286    if (event->trunk_ref) {
06287       ao2_ref(event->trunk_ref, -1);
06288       event->trunk_ref = NULL;
06289    }
06290 
06291    if (event->station) {
06292       ao2_ref(event->station, -1);
06293       event->station = NULL;
06294    }
06295 
06296    ast_free(event);
06297 }

static void sla_failed_station_destroy ( struct sla_failed_station failed_station  )  [static]

Definition at line 5511 of file app_meetme.c.

References ao2_ref, ast_free, and sla_failed_station::station.

Referenced by sla_check_failed_station(), and sla_thread().

05512 {
05513    if (failed_station->station) {
05514       ao2_ref(failed_station->station, -1);
05515       failed_station->station = NULL;
05516    }
05517 
05518    ast_free(failed_station);
05519 }

static struct sla_station* sla_find_station ( const char *  name  )  [static, read]

Definition at line 5380 of file app_meetme.c.

References ao2_find, OBJ_POINTER, and sla_stations.

Referenced by sla_build_station(), sla_state(), and sla_station_exec().

05381 {
05382    struct sla_station tmp_station = {
05383       .name = name,
05384    };
05385 
05386    return ao2_find(sla_stations, &tmp_station, OBJ_POINTER);
05387 }

static struct sla_trunk* sla_find_trunk ( const char *  name  )  [static, read]

Definition at line 5367 of file app_meetme.c.

References ao2_find, OBJ_POINTER, and sla_trunks.

Referenced by sla_add_trunk_to_station(), sla_build_trunk(), and sla_trunk_exec().

05368 {
05369    struct sla_trunk tmp_trunk = {
05370       .name = name,
05371    };
05372 
05373    return ao2_find(sla_trunks, &tmp_trunk, OBJ_POINTER);
05374 }

static struct sla_trunk_ref* sla_find_trunk_ref ( const struct sla_station station,
const struct sla_trunk trunk 
) [static, read]

Definition at line 5936 of file app_meetme.c.

References ao2_ref, and AST_LIST_TRAVERSE.

Referenced by sla_check_station_delay().

05938 {
05939    struct sla_trunk_ref *trunk_ref = NULL;
05940 
05941    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05942       if (trunk_ref->trunk == trunk)
05943          break;
05944    }
05945 
05946    ao2_ref(trunk_ref, 1);
05947 
05948    return trunk_ref;
05949 }

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.

Parameters:
station the station
name the trunk's name
Precondition:
sla_station is locked
Returns:
a pointer to the station's trunk reference. If the trunk is not found, it is not idle and barge is disabled, or if it is on hold and private hold is set, then NULL will be returned.

Definition at line 5419 of file app_meetme.c.

References ao2_ref, AST_LIST_TRAVERSE, sla_check_station_hold_access(), SLA_HOLD_PRIVATE, SLA_TRUNK_STATE_ONHOLD_BYME, and SLA_TRUNK_STATE_UP.

Referenced by sla_station_exec().

05421 {
05422    struct sla_trunk_ref *trunk_ref = NULL;
05423 
05424    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05425       if (strcasecmp(trunk_ref->trunk->name, name))
05426          continue;
05427 
05428       if ( (trunk_ref->trunk->barge_disabled 
05429          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
05430          (trunk_ref->trunk->hold_stations 
05431          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
05432          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
05433          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
05434       {
05435          trunk_ref = NULL;
05436       }
05437 
05438       break;
05439    }
05440 
05441    if (trunk_ref) {
05442       ao2_ref(trunk_ref, 1);
05443    }
05444 
05445    return trunk_ref;
05446 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 5741 of file app_meetme.c.

References ALL_TRUNK_REFS, answer_trunk_chan(), ao2_ref, ast_cond_destroy, ast_cond_init, ast_cond_wait, ast_debug, ast_dial_answered(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_state(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_destroy, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_detached_background, run_station_args::cond, run_station_args::cond_lock, RAII_VAR, run_station(), sla, sla_change_trunk_state(), sla_choose_ringing_trunk(), SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_queue_event(), sla_ringing_station_destroy(), sla_ringing_trunk_destroy(), SLA_STATION_HANGUP_NORMAL, sla_stop_ringing_station(), SLA_TRUNK_STATE_UP, run_station_args::station, sla_ringing_station::station, sla_ringing_trunk::trunk, and run_station_args::trunk_ref.

Referenced by sla_thread().

05742 {
05743    struct sla_ringing_station *ringing_station;
05744 
05745    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05746       RAII_VAR(struct sla_trunk_ref *, s_trunk_ref, NULL, unref_obj);
05747       struct sla_ringing_trunk *ringing_trunk = NULL;
05748       struct run_station_args args;
05749       enum ast_dial_result dial_res;
05750       pthread_t dont_care;
05751       ast_mutex_t cond_lock;
05752       ast_cond_t cond;
05753 
05754       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
05755       case AST_DIAL_RESULT_HANGUP:
05756       case AST_DIAL_RESULT_INVALID:
05757       case AST_DIAL_RESULT_FAILED:
05758       case AST_DIAL_RESULT_TIMEOUT:
05759       case AST_DIAL_RESULT_UNANSWERED:
05760          AST_LIST_REMOVE_CURRENT(entry);
05761          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
05762          break;
05763       case AST_DIAL_RESULT_ANSWERED:
05764          AST_LIST_REMOVE_CURRENT(entry);
05765          /* Find the appropriate trunk to answer. */
05766          ast_mutex_lock(&sla.lock);
05767          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
05768          ast_mutex_unlock(&sla.lock);
05769          if (!ringing_trunk) {
05770             /* This case happens in a bit of a race condition.  If two stations answer
05771              * the outbound call at the same time, the first one will get connected to
05772              * the trunk.  When the second one gets here, it will not see any trunks
05773              * ringing so we have no idea what to conect it to.  So, we just hang up
05774              * on it. */
05775             ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
05776             ast_dial_join(ringing_station->station->dial);
05777             ast_dial_destroy(ringing_station->station->dial);
05778             ringing_station->station->dial = NULL;
05779             sla_ringing_station_destroy(ringing_station);
05780             break;
05781          }
05782          /* Track the channel that answered this trunk */
05783          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
05784          /* Actually answer the trunk */
05785          answer_trunk_chan(ringing_trunk->trunk->chan);
05786          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05787          /* Now, start a thread that will connect this station to the trunk.  The rest of
05788           * the code here sets up the thread and ensures that it is able to save the arguments
05789           * before they are no longer valid since they are allocated on the stack. */
05790          ao2_ref(s_trunk_ref, 1);
05791          args.trunk_ref = s_trunk_ref;
05792          ao2_ref(ringing_station->station, 1);
05793          args.station = ringing_station->station;
05794          args.cond = &cond;
05795          args.cond_lock = &cond_lock;
05796          sla_ringing_trunk_destroy(ringing_trunk);
05797          sla_ringing_station_destroy(ringing_station);
05798          ast_mutex_init(&cond_lock);
05799          ast_cond_init(&cond, NULL);
05800          ast_mutex_lock(&cond_lock);
05801          ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
05802          ast_cond_wait(&cond, &cond_lock);
05803          ast_mutex_unlock(&cond_lock);
05804          ast_mutex_destroy(&cond_lock);
05805          ast_cond_destroy(&cond);
05806          break;
05807       case AST_DIAL_RESULT_TRYING:
05808       case AST_DIAL_RESULT_RINGING:
05809       case AST_DIAL_RESULT_PROGRESS:
05810       case AST_DIAL_RESULT_PROCEEDING:
05811          break;
05812       }
05813       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
05814          /* Queue up reprocessing ringing trunks, and then ringing stations again */
05815          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05816          sla_queue_event(SLA_EVENT_DIAL_STATE);
05817          break;
05818       }
05819    }
05820    AST_LIST_TRAVERSE_SAFE_END;
05821 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 6068 of file app_meetme.c.

References ast_atomic_fetchadd_int(), AST_CONTROL_HOLD, AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_indicate(), ast_softhangup(), AST_SOFTHANGUP_DEV, INACTIVE_TRUNK_REFS, sla_change_trunk_state(), SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, sla_event::station, and sla_event::trunk_ref.

Referenced by sla_thread().

06069 {
06070    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
06071    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
06072    ast_devstate_changed(AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, "SLA:%s_%s",
06073               event->station->name, event->trunk_ref->trunk->name);
06074    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
06075       INACTIVE_TRUNK_REFS, event->trunk_ref);
06076 
06077    if (event->trunk_ref->trunk->active_stations == 1) {
06078       /* The station putting it on hold is the only one on the call, so start
06079        * Music on hold to the trunk. */
06080       event->trunk_ref->trunk->on_hold = 1;
06081       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
06082    }
06083 
06084    ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
06085    event->trunk_ref->chan = NULL;
06086 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 6058 of file app_meetme.c.

References ast_mutex_lock, ast_mutex_unlock, sla, sla_hangup_stations(), and sla_ring_stations().

Referenced by sla_thread().

06059 {
06060    ast_mutex_lock(&sla.lock);
06061    sla_ring_stations();
06062    ast_mutex_unlock(&sla.lock);
06063 
06064    /* Find stations that shouldn't be ringing anymore. */
06065    sla_hangup_stations();
06066 }

static void sla_hangup_stations ( void   )  [static]

Definition at line 6030 of file app_meetme.c.

References ast_dial_destroy(), ast_dial_join(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_lock, ast_mutex_unlock, sla, sla_ringing_station_destroy(), sla_ringing_station::station, and sla_ringing_trunk::trunk.

Referenced by sla_handle_ringing_trunk_event().

06031 {
06032    struct sla_trunk_ref *trunk_ref;
06033    struct sla_ringing_station *ringing_station;
06034 
06035    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
06036       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
06037          struct sla_ringing_trunk *ringing_trunk;
06038          ast_mutex_lock(&sla.lock);
06039          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
06040             if (trunk_ref->trunk == ringing_trunk->trunk)
06041                break;
06042          }
06043          ast_mutex_unlock(&sla.lock);
06044          if (ringing_trunk)
06045             break;
06046       }
06047       if (!trunk_ref) {
06048          AST_LIST_REMOVE_CURRENT(entry);
06049          ast_dial_join(ringing_station->station->dial);
06050          ast_dial_destroy(ringing_station->station->dial);
06051          ringing_station->station->dial = NULL;
06052          sla_ringing_station_destroy(ringing_station);
06053       }
06054    }
06055    AST_LIST_TRAVERSE_SAFE_END
06056 }

static const char* sla_hold_str ( unsigned int  hold_access  )  [static]

Definition at line 1714 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01715 {
01716    const char *hold = "Unknown";
01717 
01718    switch (hold_access) {
01719    case SLA_HOLD_OPEN:
01720       hold = "Open";
01721       break;
01722    case SLA_HOLD_PRIVATE:
01723       hold = "Private";
01724    default:
01725       break;
01726    }
01727 
01728    return hold;
01729 }

static int sla_in_use ( void   )  [static]

Definition at line 7375 of file app_meetme.c.

References ao2_container_count(), sla_stations, and sla_trunks.

Referenced by sla_load_config().

static int sla_load_config ( int  reload  )  [static]

Definition at line 7380 of file app_meetme.c.

References ao2_callback, ao2_container_alloc, ast_category_browse(), ast_cond_init, ast_config_destroy(), ast_config_load, ast_log(), ast_mutex_init, ast_pthread_create, AST_PTHREADT_NULL, ast_true(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_ERROR, LOG_WARNING, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, sla, sla_build_station(), sla_build_trunk(), SLA_CONFIG_FILE, sla_in_use(), sla_station_cmp(), sla_station_hash(), sla_station_is_marked(), sla_station_mark(), sla_stations, sla_thread(), sla_trunk_cmp(), sla_trunk_hash(), sla_trunk_is_marked(), sla_trunk_mark(), sla_trunks, and type.

Referenced by load_config().

07381 {
07382    struct ast_config *cfg;
07383    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
07384    const char *cat = NULL;
07385    int res = 0;
07386    const char *val;
07387 
07388    if (!reload) {
07389       ast_mutex_init(&sla.lock);
07390       ast_cond_init(&sla.cond, NULL);
07391       sla_trunks = ao2_container_alloc(1, sla_trunk_hash, sla_trunk_cmp);
07392       sla_stations = ao2_container_alloc(1, sla_station_hash, sla_station_cmp);
07393    }
07394 
07395    if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
07396       return 0; /* Treat no config as normal */
07397    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
07398       return 0;
07399    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
07400       ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format.  Aborting.\n");
07401       return 0;
07402    }
07403 
07404    if (reload) {
07405       ao2_callback(sla_trunks, 0, sla_trunk_mark, NULL);
07406       ao2_callback(sla_stations, 0, sla_station_mark, NULL);
07407    }
07408 
07409    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
07410       sla.attempt_callerid = ast_true(val);
07411 
07412    while ((cat = ast_category_browse(cfg, cat)) && !res) {
07413       const char *type;
07414       if (!strcasecmp(cat, "general"))
07415          continue;
07416       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
07417          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
07418             SLA_CONFIG_FILE);
07419          continue;
07420       }
07421       if (!strcasecmp(type, "trunk"))
07422          res = sla_build_trunk(cfg, cat);
07423       else if (!strcasecmp(type, "station"))
07424          res = sla_build_station(cfg, cat);
07425       else {
07426          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
07427             SLA_CONFIG_FILE, type);
07428       }
07429    }
07430 
07431    ast_config_destroy(cfg);
07432 
07433    if (reload) {
07434       ao2_callback(sla_trunks, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, sla_trunk_is_marked, NULL);
07435       ao2_callback(sla_stations, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, sla_station_is_marked, NULL);
07436    }
07437 
07438    /* Start SLA event processing thread once SLA has been configured. */
07439    if (sla.thread == AST_PTHREADT_NULL && sla_in_use()) {
07440       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
07441    }
07442 
07443    return res;
07444 }

static int sla_process_timers ( struct timespec *  ts  )  [static]

Calculate the time until the next known event.

Note:
Called with sla.lock locked

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

06250 {
06251    unsigned int timeout = UINT_MAX;
06252    struct timeval wait;
06253    unsigned int change_made = 0;
06254 
06255    /* Check for ring timeouts on ringing trunks */
06256    if (sla_calc_trunk_timeouts(&timeout))
06257       change_made = 1;
06258 
06259    /* Check for ring timeouts on ringing stations */
06260    if (sla_calc_station_timeouts(&timeout))
06261       change_made = 1;
06262 
06263    /* Check for station ring delays */
06264    if (sla_calc_station_delays(&timeout))
06265       change_made = 1;
06266 
06267    /* queue reprocessing of ringing trunks */
06268    if (change_made)
06269       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
06270 
06271    /* No timeout */
06272    if (timeout == UINT_MAX)
06273       return 0;
06274 
06275    if (ts) {
06276       wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
06277       ts->tv_sec = wait.tv_sec;
06278       ts->tv_nsec = wait.tv_usec * 1000;
06279    }
06280 
06281    return 1;
06282 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]
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 2055 of file app_meetme.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_debug, AST_LIST_TRAVERSE, ast_log(), ast_strdupa, ast_strlen_zero(), ast_conference::confno, LOG_ERROR, sla_queue_event_full(), and sla_stations.

Referenced by conf_run().

02057 {
02058    struct sla_station *station;
02059    struct sla_trunk_ref *trunk_ref = NULL;
02060    char *trunk_name;
02061    struct ao2_iterator i;
02062 
02063    trunk_name = ast_strdupa(conf->confno);
02064    strsep(&trunk_name, "_");
02065    if (ast_strlen_zero(trunk_name)) {
02066       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
02067       return;
02068    }
02069 
02070    i = ao2_iterator_init(sla_stations, 0);
02071    while ((station = ao2_iterator_next(&i))) {
02072       ao2_lock(station);
02073       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
02074          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name)) {
02075             ao2_ref(trunk_ref, 1);
02076             break;
02077          }
02078       }
02079       ao2_unlock(station);
02080       if (trunk_ref) {
02081          /* station reference given to sla_queue_event_full() */
02082          break;
02083       }
02084       ao2_ref(station, -1);
02085    }
02086    ao2_iterator_destroy(&i);
02087 
02088    if (!trunk_ref) {
02089       ast_debug(1, "Trunk not found for event!\n");
02090       return;
02091    }
02092 
02093    sla_queue_event_full(type, trunk_ref, station, 1);
02094 }

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 2012 of file app_meetme.c.

References ao2_ref, ast_calloc, ast_cond_signal, AST_LIST_INSERT_TAIL, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, and sla.

Referenced by sla_queue_event(), sla_queue_event_conf(), and sla_queue_event_nolock().

02014 {
02015    struct sla_event *event;
02016 
02017    if (sla.thread == AST_PTHREADT_NULL) {
02018       ao2_ref(station, -1);
02019       ao2_ref(trunk_ref, -1);
02020       return;
02021    }
02022 
02023    if (!(event = ast_calloc(1, sizeof(*event)))) {
02024       ao2_ref(station, -1);
02025       ao2_ref(trunk_ref, -1);
02026       return;
02027    }
02028 
02029    event->type = type;
02030    event->trunk_ref = trunk_ref;
02031    event->station = station;
02032 
02033    if (!lock) {
02034       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
02035       return;
02036    }
02037 
02038    ast_mutex_lock(&sla.lock);
02039    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
02040    ast_cond_signal(&sla.cond);
02041    ast_mutex_unlock(&sla.lock);
02042 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 2044 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

02045 {
02046    sla_queue_event_full(type, NULL, NULL, 0);
02047 }

static int sla_ring_station ( struct sla_ringing_trunk ringing_trunk,
struct sla_station station 
) [static]

Ring a station.

Note:
Assumes sla.lock is locked

Definition at line 5864 of file app_meetme.c.

References ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_TRYING, ast_dial_run(), ast_dial_set_state_callback(), AST_LIST_INSERT_HEAD, ast_party_caller_free(), ast_party_caller_init(), ast_strdupa, sla, sla_create_failed_station(), sla_create_ringing_station(), sla_dial_state_callback(), and sla_ringing_trunk::trunk.

Referenced by sla_ring_stations().

05865 {
05866    char *tech, *tech_data;
05867    struct ast_dial *dial;
05868    struct sla_ringing_station *ringing_station;
05869    enum ast_dial_result res;
05870    int caller_is_saved;
05871    struct ast_party_caller caller;
05872 
05873    if (!(dial = ast_dial_create()))
05874       return -1;
05875 
05876    ast_dial_set_state_callback(dial, sla_dial_state_callback);
05877    tech_data = ast_strdupa(station->device);
05878    tech = strsep(&tech_data, "/");
05879 
05880    if (ast_dial_append(dial, tech, tech_data) == -1) {
05881       ast_dial_destroy(dial);
05882       return -1;
05883    }
05884 
05885    /* Do we need to save off the caller ID data? */
05886    caller_is_saved = 0;
05887    if (!sla.attempt_callerid) {
05888       caller_is_saved = 1;
05889       caller = ringing_trunk->trunk->chan->caller;
05890       ast_party_caller_init(&ringing_trunk->trunk->chan->caller);
05891    }
05892 
05893    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
05894    
05895    /* Restore saved caller ID */
05896    if (caller_is_saved) {
05897       ast_party_caller_free(&ringing_trunk->trunk->chan->caller);
05898       ringing_trunk->trunk->chan->caller = caller;
05899    }
05900    
05901    if (res != AST_DIAL_RESULT_TRYING) {
05902       struct sla_failed_station *failed_station;
05903       ast_dial_destroy(dial);
05904       if ((failed_station = sla_create_failed_station(station))) {
05905          AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
05906       }
05907       return -1;
05908    }
05909    if (!(ringing_station = sla_create_ringing_station(station))) {
05910       ast_dial_join(dial);
05911       ast_dial_destroy(dial);
05912       return -1;
05913    }
05914 
05915    station->dial = dial;
05916 
05917    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
05918 
05919    return 0;
05920 }

static void sla_ring_stations ( void   )  [static]

Ring stations based on current set of ringing trunks.

Note:
Assumes that sla.lock is locked

Definition at line 5989 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(), and sla_ringing_trunk::trunk.

Referenced by sla_handle_ringing_trunk_event().

05990 {
05991    struct sla_station_ref *station_ref;
05992    struct sla_ringing_trunk *ringing_trunk;
05993 
05994    /* Make sure that every station that uses at least one of the ringing
05995     * trunks, is ringing. */
05996    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05997       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
05998          int time_left;
05999 
06000          /* Is this station already ringing? */
06001          if (sla_check_ringing_station(station_ref->station))
06002             continue;
06003 
06004          /* Is this station already in a call? */
06005          if (sla_check_inuse_station(station_ref->station))
06006             continue;
06007 
06008          /* Did we fail to dial this station earlier?  If so, has it been
06009           * a minute since we tried? */
06010          if (sla_check_failed_station(station_ref->station))
06011             continue;
06012 
06013          /* If this station already timed out while this trunk was ringing,
06014           * do not dial it again for this ringing trunk. */
06015          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
06016             continue;
06017 
06018          /* Check for a ring delay in progress */
06019          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
06020          if (time_left != INT_MAX && time_left > 0)
06021             continue;
06022 
06023          /* It is time to make this station begin to ring.  Do it! */
06024          sla_ring_station(ringing_trunk, station_ref->station);
06025       }
06026    }
06027    /* Now, all of the stations that should be ringing, are ringing. */
06028 }

static void sla_ringing_station_destroy ( struct sla_ringing_station ringing_station  )  [static]

Definition at line 5486 of file app_meetme.c.

References ao2_ref, ast_free, and sla_ringing_station::station.

Referenced by sla_handle_dial_state_event(), sla_hangup_stations(), sla_stop_ringing_station(), and sla_thread().

05487 {
05488    if (ringing_station->station) {
05489       ao2_ref(ringing_station->station, -1);
05490       ringing_station->station = NULL;
05491    }
05492 
05493    ast_free(ringing_station);
05494 }

static void sla_ringing_trunk_destroy ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 6714 of file app_meetme.c.

References ao2_ref, ast_free, and sla_ringing_trunk::trunk.

Referenced by sla_handle_dial_state_event(), sla_station_exec(), sla_stop_ringing_trunk(), and sla_trunk_exec().

06715 {
06716    if (ringing_trunk->trunk) {
06717       ao2_ref(ringing_trunk->trunk, -1);
06718       ringing_trunk->trunk = NULL;
06719    }
06720 
06721    ast_free(ringing_trunk);
06722 }

static char* sla_show_stations ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1805 of file app_meetme.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_cli(), AST_LIST_TRAVERSE, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, S_OR, sla_hold_str(), sla_stations, trunkstate2str(), and ast_cli_entry::usage.

01806 {
01807    struct ao2_iterator i;
01808    struct sla_station *station;
01809 
01810    switch (cmd) {
01811    case CLI_INIT:
01812       e->command = "sla show stations";
01813       e->usage =
01814          "Usage: sla show stations\n"
01815          "       This will list all stations defined in sla.conf\n";
01816       return NULL;
01817    case CLI_GENERATE:
01818       return NULL;
01819    }
01820 
01821    ast_cli(a->fd, "\n" 
01822                "=============================================================\n"
01823                "=== Configured SLA Stations =================================\n"
01824                "=============================================================\n"
01825                "===\n");
01826    i = ao2_iterator_init(sla_stations, 0);
01827    for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
01828       struct sla_trunk_ref *trunk_ref;
01829       char ring_timeout[16] = "(none)";
01830       char ring_delay[16] = "(none)";
01831 
01832       ao2_lock(station);
01833 
01834       if (station->ring_timeout) {
01835          snprintf(ring_timeout, sizeof(ring_timeout), 
01836             "%u", station->ring_timeout);
01837       }
01838       if (station->ring_delay) {
01839          snprintf(ring_delay, sizeof(ring_delay), 
01840             "%u", station->ring_delay);
01841       }
01842       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01843                   "=== Station Name:    %s\n"
01844                   "=== ==> Device:      %s\n"
01845                   "=== ==> AutoContext: %s\n"
01846                   "=== ==> RingTimeout: %s\n"
01847                   "=== ==> RingDelay:   %s\n"
01848                   "=== ==> HoldAccess:  %s\n"
01849                   "=== ==> Trunks ...\n",
01850                   station->name, station->device,
01851                   S_OR(station->autocontext, "(none)"), 
01852                   ring_timeout, ring_delay,
01853                   sla_hold_str(station->hold_access));
01854       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01855          if (trunk_ref->ring_timeout) {
01856             snprintf(ring_timeout, sizeof(ring_timeout),
01857                "%u", trunk_ref->ring_timeout);
01858          } else
01859             strcpy(ring_timeout, "(none)");
01860          if (trunk_ref->ring_delay) {
01861             snprintf(ring_delay, sizeof(ring_delay),
01862                "%u", trunk_ref->ring_delay);
01863          } else
01864             strcpy(ring_delay, "(none)");
01865             ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
01866                      "===       ==> State:       %s\n"
01867                      "===       ==> RingTimeout: %s\n"
01868                      "===       ==> RingDelay:   %s\n",
01869                      trunk_ref->trunk->name,
01870                      trunkstate2str(trunk_ref->state),
01871                      ring_timeout, ring_delay);
01872       }
01873       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01874                   "===\n");
01875 
01876       ao2_unlock(station);
01877    }
01878    ao2_iterator_destroy(&i);
01879    ast_cli(a->fd, "============================================================\n"
01880                "\n");
01881 
01882    return CLI_SUCCESS;
01883 }

static char* sla_show_trunks ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1731 of file app_meetme.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, ast_cli(), AST_LIST_TRAVERSE, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, S_OR, sla_hold_str(), sla_trunks, and ast_cli_entry::usage.

01732 {
01733    struct ao2_iterator i;
01734    struct sla_trunk *trunk;
01735 
01736    switch (cmd) {
01737    case CLI_INIT:
01738       e->command = "sla show trunks";
01739       e->usage =
01740          "Usage: sla show trunks\n"
01741          "       This will list all trunks defined in sla.conf\n";
01742       return NULL;
01743    case CLI_GENERATE:
01744       return NULL;
01745    }
01746 
01747    ast_cli(a->fd, "\n"
01748                "=============================================================\n"
01749                "=== Configured SLA Trunks ===================================\n"
01750                "=============================================================\n"
01751                "===\n");
01752    i = ao2_iterator_init(sla_trunks, 0);
01753    for (; (trunk = ao2_iterator_next(&i)); ao2_ref(trunk, -1)) {
01754       struct sla_station_ref *station_ref;
01755       char ring_timeout[16] = "(none)";
01756 
01757       ao2_lock(trunk);
01758 
01759       if (trunk->ring_timeout) {
01760          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01761       }
01762 
01763       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01764                   "=== Trunk Name:       %s\n"
01765                   "=== ==> Device:       %s\n"
01766                   "=== ==> AutoContext:  %s\n"
01767                   "=== ==> RingTimeout:  %s\n"
01768                   "=== ==> BargeAllowed: %s\n"
01769                   "=== ==> HoldAccess:   %s\n"
01770                   "=== ==> Stations ...\n",
01771                   trunk->name, trunk->device, 
01772                   S_OR(trunk->autocontext, "(none)"), 
01773                   ring_timeout,
01774                   trunk->barge_disabled ? "No" : "Yes",
01775                   sla_hold_str(trunk->hold_access));
01776 
01777       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
01778          ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
01779       }
01780 
01781       ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
01782 
01783       ao2_unlock(trunk);
01784    }
01785    ao2_iterator_destroy(&i);
01786    ast_cli(a->fd, "=============================================================\n\n");
01787 
01788    return CLI_SUCCESS;
01789 }

static enum ast_device_state sla_state ( const char *  data  )  [static]

Definition at line 6835 of file app_meetme.c.

References ao2_lock, ao2_unlock, AST_DEVICE_INVALID, AST_LIST_TRAVERSE, ast_log(), ast_strdupa, LOG_ERROR, RAII_VAR, sla_find_station(), and sla_state_to_devstate().

Referenced by load_module().

06836 {
06837    char *buf, *station_name, *trunk_name;
06838    RAII_VAR(struct sla_station *, station, NULL, unref_obj);
06839    struct sla_trunk_ref *trunk_ref;
06840    enum ast_device_state res = AST_DEVICE_INVALID;
06841 
06842    trunk_name = buf = ast_strdupa(data);
06843    station_name = strsep(&trunk_name, "_");
06844 
06845    station = sla_find_station(station_name);
06846    if (station) {
06847       ao2_lock(station);
06848       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06849          if (!strcasecmp(trunk_name, trunk_ref->trunk->name)) {
06850             res = sla_state_to_devstate(trunk_ref->state);
06851             break;
06852          }
06853       }
06854       ao2_unlock(station);
06855    }
06856 
06857    if (res == AST_DEVICE_INVALID) {
06858       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
06859          trunk_name, station_name);
06860    }
06861 
06862    return res;
06863 }

static enum ast_device_state sla_state_to_devstate ( enum sla_trunk_state  state  )  [static]
static int sla_station_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 6936 of file app_meetme.c.

References CMP_MATCH, and CMP_STOP.

Referenced by sla_load_config().

06937 {
06938    struct sla_station *station = obj, *station2 = arg;
06939 
06940    return !strcasecmp(station->name, station2->name) ? CMP_MATCH | CMP_STOP : 0;
06941 }

static void sla_station_destructor ( void *  obj  )  [static]

Definition at line 6889 of file app_meetme.c.

References ast_context_remove_extension(), ast_debug, AST_LIST_TRAVERSE, AST_MAX_APP, AST_MAX_EXTENSION, ast_string_field_free_memory, ast_strlen_zero(), exten, PRIORITY_HINT, sla_registrar, and sla_station_release_refs().

Referenced by sla_build_station().

06890 {
06891    struct sla_station *station = obj;
06892 
06893    ast_debug(1, "sla_station destructor for '%s'\n", station->name);
06894 
06895    if (!ast_strlen_zero(station->autocontext)) {
06896       struct sla_trunk_ref *trunk_ref;
06897 
06898       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06899          char exten[AST_MAX_EXTENSION];
06900          char hint[AST_MAX_APP];
06901          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06902          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06903          ast_context_remove_extension(station->autocontext, exten, 
06904             1, sla_registrar);
06905          ast_context_remove_extension(station->autocontext, hint, 
06906             PRIORITY_HINT, sla_registrar);
06907       }
06908    }
06909 
06910    sla_station_release_refs(station, NULL, 0);
06911 
06912    ast_string_field_free_memory(station);
06913 }

static int sla_station_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 6515 of file app_meetme.c.

References admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), ao2_lock, ao2_ref, ao2_unlock, ast_answer(), ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_cond_destroy, ast_cond_init, ast_cond_wait, AST_CONTROL_UNHOLD, ast_debug, AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_destroy, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_detached_background, ast_set_flag64, ast_strdupa, ast_strlen_zero(), build_conf(), conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dial_trunk(), dispose_conf(), LOG_NOTICE, LOG_WARNING, MAX_CONFNUM, pbx_builtin_setvar_helper(), RAII_VAR, sla, sla_change_trunk_state(), sla_choose_idle_trunk(), SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_find_station(), sla_find_trunk_ref_byname(), sla_queue_event(), sla_ringing_trunk_destroy(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, sla_ringing_trunk::trunk, and dial_trunk_args::trunk_ref.

Referenced by load_module().

06516 {
06517    char *station_name, *trunk_name;
06518    RAII_VAR(struct sla_station *, station, NULL, unref_obj);
06519    RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, unref_obj);
06520    char conf_name[MAX_CONFNUM];
06521    struct ast_flags64 conf_flags = { 0 };
06522    struct ast_conference *conf;
06523 
06524    if (ast_strlen_zero(data)) {
06525       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
06526       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06527       return 0;
06528    }
06529 
06530    trunk_name = ast_strdupa(data);
06531    station_name = strsep(&trunk_name, "_");
06532 
06533    if (ast_strlen_zero(station_name)) {
06534       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
06535       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06536       return 0;
06537    }
06538 
06539    station = sla_find_station(station_name);
06540 
06541    if (!station) {
06542       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
06543       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06544       return 0;
06545    }
06546 
06547    ao2_lock(station);
06548    if (!ast_strlen_zero(trunk_name)) {
06549       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
06550    } else {
06551       trunk_ref = sla_choose_idle_trunk(station);
06552    }
06553    ao2_unlock(station);
06554 
06555    if (!trunk_ref) {
06556       if (ast_strlen_zero(trunk_name))
06557          ast_log(LOG_NOTICE, "No trunks available for call.\n");
06558       else {
06559          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
06560             "'%s' due to access controls.\n", trunk_name);
06561       }
06562       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
06563       return 0;
06564    }
06565 
06566    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
06567       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
06568          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06569       else {
06570          trunk_ref->state = SLA_TRUNK_STATE_UP;
06571          ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE,
06572                     "SLA:%s_%s", station->name, trunk_ref->trunk->name);
06573       }
06574    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
06575       struct sla_ringing_trunk *ringing_trunk;
06576 
06577       ast_mutex_lock(&sla.lock);
06578       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
06579          if (ringing_trunk->trunk == trunk_ref->trunk) {
06580             AST_LIST_REMOVE_CURRENT(entry);
06581             break;
06582          }
06583       }
06584       AST_LIST_TRAVERSE_SAFE_END
06585       ast_mutex_unlock(&sla.lock);
06586 
06587       if (ringing_trunk) {
06588          answer_trunk_chan(ringing_trunk->trunk->chan);
06589          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06590 
06591          sla_ringing_trunk_destroy(ringing_trunk);
06592 
06593          /* Queue up reprocessing ringing trunks, and then ringing stations again */
06594          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06595          sla_queue_event(SLA_EVENT_DIAL_STATE);
06596       }
06597    }
06598 
06599    trunk_ref->chan = chan;
06600 
06601    if (!trunk_ref->trunk->chan) {
06602       ast_mutex_t cond_lock;
06603       ast_cond_t cond;
06604       pthread_t dont_care;
06605       struct dial_trunk_args args = {
06606          .trunk_ref = trunk_ref,
06607          .station = station,
06608          .cond_lock = &cond_lock,
06609          .cond = &cond,
06610       };
06611       ao2_ref(trunk_ref, 1);
06612       ao2_ref(station, 1);
06613       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06614       /* Create a thread to dial the trunk and dump it into the conference.
06615        * However, we want to wait until the trunk has been dialed and the
06616        * conference is created before continuing on here. */
06617       ast_autoservice_start(chan);
06618       ast_mutex_init(&cond_lock);
06619       ast_cond_init(&cond, NULL);
06620       ast_mutex_lock(&cond_lock);
06621       ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
06622       ast_cond_wait(&cond, &cond_lock);
06623       ast_mutex_unlock(&cond_lock);
06624       ast_mutex_destroy(&cond_lock);
06625       ast_cond_destroy(&cond);
06626       ast_autoservice_stop(chan);
06627       if (!trunk_ref->trunk->chan) {
06628          ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
06629          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
06630          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06631          trunk_ref->chan = NULL;
06632          return 0;
06633       }
06634    }
06635 
06636    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
06637       trunk_ref->trunk->on_hold) {
06638       trunk_ref->trunk->on_hold = 0;
06639       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
06640       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06641    }
06642 
06643    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
06644    ast_set_flag64(&conf_flags, 
06645       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
06646    ast_answer(chan);
06647    conf = build_conf(conf_name, "", "", 0, 0, 1, chan, NULL);
06648    if (conf) {
06649       conf_run(chan, conf, &conf_flags, NULL);
06650       dispose_conf(conf);
06651       conf = NULL;
06652    }
06653    trunk_ref->chan = NULL;
06654    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
06655       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
06656       strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
06657       admin_exec(NULL, conf_name);
06658       trunk_ref->trunk->hold_stations = 0;
06659       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06660    }
06661    
06662    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
06663 
06664    return 0;
06665 }

static int sla_station_hash ( const void *  obj,
const int  flags 
) [static]

Definition at line 6929 of file app_meetme.c.

References ast_str_case_hash().

Referenced by sla_load_config().

06930 {
06931    const struct sla_station *station = obj;
06932 
06933    return ast_str_case_hash(station->name);
06934 }

static int sla_station_is_marked ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 7347 of file app_meetme.c.

References ao2_lock, ao2_ref, ao2_unlock, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, CMP_MATCH, and sla_station_release_refs().

Referenced by sla_load_config().

07348 {
07349    struct sla_station *station = obj;
07350 
07351    ao2_lock(station);
07352 
07353    if (station->mark) {
07354       /* Only remove all of the trunk references if the station itself is going away */
07355       sla_station_release_refs(station, NULL, 0);
07356    } else {
07357       struct sla_trunk_ref *trunk_ref;
07358 
07359       /* Otherwise only remove references to trunks no longer in the config */
07360       AST_LIST_TRAVERSE_SAFE_BEGIN(&station->trunks, trunk_ref, entry) {
07361          if (!trunk_ref->mark) {
07362             continue;
07363          }
07364          AST_LIST_REMOVE_CURRENT(entry);
07365          ao2_ref(trunk_ref, -1);
07366       }
07367       AST_LIST_TRAVERSE_SAFE_END
07368    }
07369 
07370    ao2_unlock(station);
07371 
07372    return station->mark ? CMP_MATCH : 0;
07373 }

static int sla_station_mark ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 7301 of file app_meetme.c.

References ao2_lock, ao2_unlock, and AST_LIST_TRAVERSE.

Referenced by sla_load_config().

07302 {
07303    struct sla_station *station = obj;
07304    struct sla_trunk_ref *trunk_ref;
07305 
07306    ao2_lock(station);
07307 
07308    station->mark = 1;
07309 
07310    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
07311       trunk_ref->mark = 1;
07312    }
07313 
07314    ao2_unlock(station);
07315 
07316    return 0;
07317 }

static void sla_station_ref_destructor ( void *  obj  )  [static]

Definition at line 5448 of file app_meetme.c.

References ao2_ref.

Referenced by sla_create_station_ref().

05449 {
05450    struct sla_station_ref *station_ref = obj;
05451 
05452    if (station_ref->station) {
05453       ao2_ref(station_ref->station, -1);
05454       station_ref->station = NULL;
05455    }
05456 }

static int sla_station_release_refs ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 6877 of file app_meetme.c.

References ao2_ref, and AST_LIST_REMOVE_HEAD.

Referenced by sla_destroy(), sla_station_destructor(), and sla_station_is_marked().

06878 {
06879    struct sla_station *station = obj;
06880    struct sla_trunk_ref *trunk_ref;
06881 
06882    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry))) {
06883       ao2_ref(trunk_ref, -1);
06884    }
06885 
06886    return 0;
06887 }

static void sla_stop_ringing_station ( struct sla_ringing_station ringing_station,
enum sla_station_hangup  hangup 
) [static]

Definition at line 5641 of file app_meetme.c.

References ast_dial_destroy(), ast_dial_join(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, sla, sla_create_station_ref(), sla_ringing_station_destroy(), SLA_STATION_HANGUP_NORMAL, sla_ringing_station::station, and sla_ringing_trunk::trunk.

Referenced by sla_calc_station_timeouts(), and sla_handle_dial_state_event().

05643 {
05644    struct sla_ringing_trunk *ringing_trunk;
05645    struct sla_trunk_ref *trunk_ref;
05646    struct sla_station_ref *station_ref;
05647 
05648    ast_dial_join(ringing_station->station->dial);
05649    ast_dial_destroy(ringing_station->station->dial);
05650    ringing_station->station->dial = NULL;
05651 
05652    if (hangup == SLA_STATION_HANGUP_NORMAL)
05653       goto done;
05654 
05655    /* If the station is being hung up because of a timeout, then add it to the
05656     * list of timed out stations on each of the ringing trunks.  This is so
05657     * that when doing further processing to figure out which stations should be
05658     * ringing, which trunk to answer, determining timeouts, etc., we know which
05659     * ringing trunks we should ignore. */
05660    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05661       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05662          if (ringing_trunk->trunk == trunk_ref->trunk)
05663             break;
05664       }
05665       if (!trunk_ref)
05666          continue;
05667       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
05668          continue;
05669       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
05670    }
05671 
05672 done:
05673    sla_ringing_station_destroy(ringing_station);
05674 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 5625 of file app_meetme.c.

References admin_exec(), ALL_TRUNK_REFS, ao2_ref, AST_LIST_REMOVE_HEAD, sla_change_trunk_state(), sla_ringing_trunk_destroy(), SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by sla_calc_trunk_timeouts().

05626 {
05627    char buf[80];
05628    struct sla_station_ref *station_ref;
05629 
05630    snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
05631    admin_exec(NULL, buf);
05632    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05633 
05634    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry))) {
05635       ao2_ref(station_ref, -1);
05636    }
05637 
05638    sla_ringing_trunk_destroy(ringing_trunk);
05639 }

static void* sla_thread ( void *  data  )  [static]

Definition at line 6299 of file app_meetme.c.

References ast_cond_timedwait, ast_cond_wait, AST_LIST_EMPTY, AST_LIST_REMOVE_HEAD, ast_mutex_lock, ast_mutex_unlock, sla, sla_event_destroy(), SLA_EVENT_DIAL_STATE, SLA_EVENT_HOLD, SLA_EVENT_RINGING_TRUNK, sla_failed_station_destroy(), sla_handle_dial_state_event(), sla_handle_hold_event(), sla_handle_ringing_trunk_event(), sla_process_timers(), sla_ringing_station_destroy(), and sla_event::type.

Referenced by sla_load_config().

06300 {
06301    struct sla_failed_station *failed_station;
06302    struct sla_ringing_station *ringing_station;
06303 
06304    ast_mutex_lock(&sla.lock);
06305 
06306    while (!sla.stop) {
06307       struct sla_event *event;
06308       struct timespec ts = { 0, };
06309       unsigned int have_timeout = 0;
06310 
06311       if (AST_LIST_EMPTY(&sla.event_q)) {
06312          if ((have_timeout = sla_process_timers(&ts)))
06313             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
06314          else
06315             ast_cond_wait(&sla.cond, &sla.lock);
06316          if (sla.stop)
06317             break;
06318       }
06319 
06320       if (have_timeout)
06321          sla_process_timers(NULL);
06322 
06323       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
06324          ast_mutex_unlock(&sla.lock);
06325          switch (event->type) {
06326          case SLA_EVENT_HOLD:
06327             sla_handle_hold_event(event);
06328             break;
06329          case SLA_EVENT_DIAL_STATE:
06330             sla_handle_dial_state_event();
06331             break;
06332          case SLA_EVENT_RINGING_TRUNK:
06333             sla_handle_ringing_trunk_event();
06334             break;
06335          }
06336          sla_event_destroy(event);
06337          ast_mutex_lock(&sla.lock);
06338       }
06339    }
06340 
06341    ast_mutex_unlock(&sla.lock);
06342 
06343    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry))) {
06344       sla_ringing_station_destroy(ringing_station);
06345    }
06346 
06347    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry))) {
06348       sla_failed_station_destroy(failed_station);
06349    }
06350 
06351    return NULL;
06352 }

static int sla_trunk_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 6922 of file app_meetme.c.

References CMP_MATCH, and CMP_STOP.

Referenced by sla_load_config().

06923 {
06924    struct sla_trunk *trunk = obj, *trunk2 = arg;
06925 
06926    return !strcasecmp(trunk->name, trunk2->name) ? CMP_MATCH | CMP_STOP : 0;
06927 }

static void sla_trunk_destructor ( void *  obj  )  [static]

Definition at line 6982 of file app_meetme.c.

References ast_context_remove_extension(), ast_debug, ast_string_field_free_memory, ast_strlen_zero(), sla_registrar, and sla_trunk_release_refs().

Referenced by sla_build_trunk().

06983 {
06984    struct sla_trunk *trunk = obj;
06985 
06986    ast_debug(1, "sla_trunk destructor for '%s'\n", trunk->name);
06987 
06988    if (!ast_strlen_zero(trunk->autocontext)) {
06989       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
06990    }
06991 
06992    sla_trunk_release_refs(trunk, NULL, 0);
06993 
06994    ast_string_field_free_memory(trunk);
06995 }

static int sla_trunk_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 6737 of file app_meetme.c.

References ALL_TRUNK_REFS, args, AST_APP_ARG, ast_app_parse_options(), AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_set_flag64, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, build_conf(), conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, dispose_conf(), LOG_ERROR, MAX_CONFNUM, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), queue_ringing_trunk(), RAII_VAR, sla, sla_change_trunk_state(), SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), sla_ringing_trunk_destroy(), SLA_TRUNK_OPT_ARG_ARRAY_SIZE, SLA_TRUNK_OPT_MOH, SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by load_module().

06738 {
06739    char conf_name[MAX_CONFNUM];
06740    struct ast_conference *conf;
06741    struct ast_flags64 conf_flags = { 0 };
06742    RAII_VAR(struct sla_trunk *, trunk, NULL, unref_obj);
06743    struct sla_ringing_trunk *ringing_trunk;
06744    AST_DECLARE_APP_ARGS(args,
06745       AST_APP_ARG(trunk_name);
06746       AST_APP_ARG(options);
06747    );
06748    char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
06749    struct ast_flags opt_flags = { 0 };
06750    char *parse;
06751 
06752    if (ast_strlen_zero(data)) {
06753       ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
06754       return -1;
06755    }
06756 
06757    parse = ast_strdupa(data);
06758    AST_STANDARD_APP_ARGS(args, parse);
06759    if (args.argc == 2) {
06760       if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
06761          ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
06762          return -1;
06763       }
06764    }
06765 
06766    trunk = sla_find_trunk(args.trunk_name);
06767 
06768    if (!trunk) {
06769       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
06770       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06771       return 0;
06772    }
06773 
06774    if (trunk->chan) {
06775       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
06776          args.trunk_name);
06777       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06778       return 0;
06779    }
06780 
06781    trunk->chan = chan;
06782 
06783    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
06784       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06785       return 0;
06786    }
06787 
06788    snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
06789    conf = build_conf(conf_name, "", "", 1, 1, 1, chan, NULL);
06790    if (!conf) {
06791       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06792       return 0;
06793    }
06794    ast_set_flag64(&conf_flags, 
06795       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
06796 
06797    if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
06798       ast_indicate(chan, -1);
06799       ast_set_flag64(&conf_flags, CONFFLAG_MOH);
06800    } else
06801       ast_indicate(chan, AST_CONTROL_RINGING);
06802 
06803    conf_run(chan, conf, &conf_flags, opts);
06804    dispose_conf(conf);
06805    conf = NULL;
06806    trunk->chan = NULL;
06807    trunk->on_hold = 0;
06808 
06809    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06810 
06811    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
06812       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
06813 
06814    /* Remove the entry from the list of ringing trunks if it is still there. */
06815    ast_mutex_lock(&sla.lock);
06816    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
06817       if (ringing_trunk->trunk == trunk) {
06818          AST_LIST_REMOVE_CURRENT(entry);
06819          break;
06820       }
06821    }
06822    AST_LIST_TRAVERSE_SAFE_END;
06823    ast_mutex_unlock(&sla.lock);
06824    if (ringing_trunk) {
06825       sla_ringing_trunk_destroy(ringing_trunk);
06826       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
06827       /* Queue reprocessing of ringing trunks to make stations stop ringing
06828        * that shouldn't be ringing after this trunk stopped. */
06829       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06830    }
06831 
06832    return 0;
06833 }

static int sla_trunk_hash ( const void *  obj,
const int  flags 
) [static]

Definition at line 6915 of file app_meetme.c.

References ast_str_case_hash().

Referenced by sla_load_config().

06916 {
06917    const struct sla_trunk *trunk = obj;
06918 
06919    return ast_str_case_hash(trunk->name);
06920 }

static int sla_trunk_is_marked ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 7319 of file app_meetme.c.

References ao2_lock, ao2_ref, ao2_unlock, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, CMP_MATCH, and sla_trunk_release_refs().

Referenced by sla_load_config().

07320 {
07321    struct sla_trunk *trunk = obj;
07322 
07323    ao2_lock(trunk);
07324 
07325    if (trunk->mark) {
07326       /* Only remove all of the station references if the trunk itself is going away */
07327       sla_trunk_release_refs(trunk, NULL, 0);
07328    } else {
07329       struct sla_station_ref *station_ref;
07330 
07331       /* Otherwise only remove references to stations no longer in the config */
07332       AST_LIST_TRAVERSE_SAFE_BEGIN(&trunk->stations, station_ref, entry) {
07333          if (!station_ref->mark) {
07334             continue;
07335          }
07336          AST_LIST_REMOVE_CURRENT(entry);
07337          ao2_ref(station_ref, -1);
07338       }
07339       AST_LIST_TRAVERSE_SAFE_END
07340    }
07341 
07342    ao2_unlock(trunk);
07343 
07344    return trunk->mark ? CMP_MATCH : 0;
07345 }

static int sla_trunk_mark ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 7283 of file app_meetme.c.

References ao2_lock, ao2_unlock, and AST_LIST_TRAVERSE.

Referenced by sla_load_config().

07284 {
07285    struct sla_trunk *trunk = obj;
07286    struct sla_station_ref *station_ref;
07287 
07288    ao2_lock(trunk);
07289 
07290    trunk->mark = 1;
07291 
07292    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
07293       station_ref->mark = 1;
07294    }
07295 
07296    ao2_unlock(trunk);
07297 
07298    return 0;
07299 }

static void sla_trunk_ref_destructor ( void *  obj  )  [static]

Definition at line 6667 of file app_meetme.c.

References ao2_ref.

Referenced by create_trunk_ref().

06668 {
06669    struct sla_trunk_ref *trunk_ref = obj;
06670 
06671    if (trunk_ref->trunk) {
06672       ao2_ref(trunk_ref->trunk, -1);
06673       trunk_ref->trunk = NULL;
06674    }
06675 }

static int sla_trunk_release_refs ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 6865 of file app_meetme.c.

References ao2_ref, and AST_LIST_REMOVE_HEAD.

Referenced by sla_destroy(), sla_trunk_destructor(), and sla_trunk_is_marked().

06866 {
06867    struct sla_trunk *trunk = obj;
06868    struct sla_station_ref *station_ref;
06869 
06870    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry))) {
06871       ao2_ref(station_ref, -1);
06872    }
06873 
06874    return 0;
06875 }

static const char* trunkstate2str ( enum sla_trunk_state  state  )  [static]

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

01792 {
01793 #define S(e) case e: return # e;
01794    switch (state) {
01795    S(SLA_TRUNK_STATE_IDLE)
01796    S(SLA_TRUNK_STATE_RINGING)
01797    S(SLA_TRUNK_STATE_UP)
01798    S(SLA_TRUNK_STATE_ONHOLD)
01799    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01800    }
01801    return "Uknown State";
01802 #undef S
01803 }

static void tweak_listen_volume ( struct ast_conf_user user,
enum volume_action  action 
) [static]

Definition at line 1114 of file app_meetme.c.

References volume::actual, volume::desired, ast_conf_user::listen, set_listen_volume(), and tweak_volume().

Referenced by admin_exec(), meetme_menu_admin(), meetme_menu_normal(), user_listen_voldown_cb(), and user_listen_volup_cb().

01115 {
01116    tweak_volume(&user->listen, action);
01117    /* attempt to make the adjustment in the channel driver;
01118       if successful, don't adjust in the frame reading routine
01119    */
01120    if (!set_listen_volume(user, user->listen.desired))
01121       user->listen.actual = 0;
01122    else
01123       user->listen.actual = user->listen.desired;
01124 }

static void tweak_talk_volume ( struct ast_conf_user user,
enum volume_action  action 
) [static]

Definition at line 1102 of file app_meetme.c.

References volume::actual, volume::desired, set_talk_volume(), ast_conf_user::talk, and tweak_volume().

Referenced by admin_exec(), meetme_menu_admin(), meetme_menu_normal(), user_talk_voldown_cb(), and user_talk_volup_cb().

01103 {
01104    tweak_volume(&user->talk, action);
01105    /* attempt to make the adjustment in the channel driver;
01106       if successful, don't adjust in the frame reading routine
01107    */
01108    if (!set_talk_volume(user, user->talk.desired))
01109       user->talk.actual = 0;
01110    else
01111       user->talk.actual = user->talk.desired;
01112 }

static void tweak_volume ( struct volume vol,
enum volume_action  action 
) [static]

Definition at line 1067 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

01068 {
01069    switch (action) {
01070    case VOL_UP:
01071       switch (vol->desired) { 
01072       case 5:
01073          break;
01074       case 0:
01075          vol->desired = 2;
01076          break;
01077       case -2:
01078          vol->desired = 0;
01079          break;
01080       default:
01081          vol->desired++;
01082          break;
01083       }
01084       break;
01085    case VOL_DOWN:
01086       switch (vol->desired) {
01087       case -5:
01088          break;
01089       case 2:
01090          vol->desired = 0;
01091          break;
01092       case 0:
01093          vol->desired = -2;
01094          break;
01095       default:
01096          vol->desired--;
01097          break;
01098       }
01099    }
01100 }

static int unload_module ( void   )  [static]

Definition at line 7705 of file app_meetme.c.

References ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_data_unregister, ast_devstate_prov_del(), ast_manager_unregister(), AST_TEST_UNREGISTER, ast_unload_realtime(), ast_unregister_application(), and sla_destroy().

07706 {
07707    int res = 0;
07708    
07709    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07710    res = ast_manager_unregister("MeetmeMute");
07711    res |= ast_manager_unregister("MeetmeUnmute");
07712    res |= ast_manager_unregister("MeetmeList");
07713    res |= ast_unregister_application(app4);
07714    res |= ast_unregister_application(app3);
07715    res |= ast_unregister_application(app2);
07716    res |= ast_unregister_application(app);
07717    res |= ast_unregister_application(slastation_app);
07718    res |= ast_unregister_application(slatrunk_app);
07719 
07720 #ifdef TEST_FRAMEWORK
07721    AST_TEST_UNREGISTER(test_meetme_data_provider);
07722 #endif
07723    ast_data_unregister(NULL);
07724 
07725    ast_devstate_prov_del("Meetme");
07726    ast_devstate_prov_del("SLA");
07727    
07728    sla_destroy();
07729    
07730    res |= ast_custom_function_unregister(&meetme_info_acf);
07731    ast_unload_realtime("meetme");
07732 
07733    return res;
07734 }

static int user_add_provider_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 7556 of file app_meetme.c.

References volume::actual, ast_channel_data_add_structure(), ast_data_add_int(), ast_data_add_node(), ast_data_add_structure, ast_conf_user::chan, volume::desired, ast_conf_user::listen, and ast_conf_user::talk.

Referenced by meetme_data_provider_get().

07557 {
07558    struct ast_data *data_meetme_user;
07559    struct ast_data *data_meetme_user_channel;
07560    struct ast_data *data_meetme_user_volume;
07561 
07562    struct ast_conf_user *user = obj;
07563    struct ast_data *data_meetme_users = arg;
07564 
07565    data_meetme_user = ast_data_add_node(data_meetme_users, "user");
07566    if (!data_meetme_user) {
07567       return 0;
07568    }
07569    /* user structure */
07570    ast_data_add_structure(ast_conf_user, data_meetme_user, user);
07571 
07572    /* user's channel */
07573    data_meetme_user_channel = ast_data_add_node(data_meetme_user, "channel");
07574    if (!data_meetme_user_channel) {
07575       return 0;
07576    }
07577 
07578    ast_channel_data_add_structure(data_meetme_user_channel, user->chan, 1);
07579 
07580    /* volume structure */
07581    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "listen-volume");
07582    if (!data_meetme_user_volume) {
07583       return 0;
07584    }
07585    ast_data_add_int(data_meetme_user_volume, "desired", user->listen.desired);
07586    ast_data_add_int(data_meetme_user_volume, "actual", user->listen.actual);
07587 
07588    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "talk-volume");
07589    if (!data_meetme_user_volume) {
07590       return 0;
07591    }
07592    ast_data_add_int(data_meetme_user_volume, "desired", user->talk.desired);
07593    ast_data_add_int(data_meetme_user_volume, "actual", user->talk.actual);
07594 
07595    return 0;
07596 }

static int user_chan_cb ( void *  obj,
void *  args,
int  flags 
) [static]

Definition at line 4778 of file app_meetme.c.

References ast_conf_user::chan, CMP_MATCH, and CMP_STOP.

Referenced by channel_admin_exec().

04779 {
04780    struct ast_conf_user *user = obj;
04781    const char *channel = args;
04782 
04783    if (!strcmp(user->chan->name, channel)) {
04784       return (CMP_MATCH | CMP_STOP);
04785    }
04786 
04787    return 0;
04788 }

static int user_listen_voldown_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4750 of file app_meetme.c.

References tweak_listen_volume(), and VOL_DOWN.

Referenced by admin_exec().

04751 {
04752    struct ast_conf_user *user = obj;
04753    tweak_listen_volume(user, VOL_DOWN);
04754    return 0;
04755 }

static int user_listen_volup_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4743 of file app_meetme.c.

References tweak_listen_volume(), and VOL_UP.

Referenced by admin_exec().

04744 {
04745    struct ast_conf_user *user = obj;
04746    tweak_listen_volume(user, VOL_UP);
04747    return 0;
04748 }

static int user_max_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1187 of file app_meetme.c.

References ast_conf_user::user_no.

Referenced by admin_exec(), conf_run(), and meetme_menu_admin().

01188 {
01189    struct ast_conf_user *user = obj;
01190    int *max_no = arg;
01191 
01192    if (user->user_no > *max_no) {
01193       *max_no = user->user_no;
01194    }
01195 
01196    return 0;
01197 }

static int user_no_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1175 of file app_meetme.c.

References CMP_MATCH, CMP_STOP, and ast_conf_user::user_no.

Referenced by build_conf().

01176 {
01177    struct ast_conf_user *user = obj;
01178    int *user_no = arg;
01179 
01180    if (user->user_no == *user_no) {
01181       return (CMP_MATCH | CMP_STOP);
01182    }
01183 
01184    return 0;
01185 }

static int user_reset_vol_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4771 of file app_meetme.c.

References reset_volumes().

Referenced by admin_exec().

04772 {
04773    struct ast_conf_user *user = obj;
04774    reset_volumes(user);
04775    return 0;
04776 }

static int user_set_kickme_cb ( void *  obj,
void *  check_admin_arg,
int  flags 
) [static]

Definition at line 2299 of file app_meetme.c.

References ADMINFLAG_KICKME, ast_conf_user::adminflags, ast_test_flag64, CONFFLAG_ADMIN, and ast_conf_user::userflags.

Referenced by admin_exec(), and meetme_menu_admin_extended().

02300 {
02301    struct ast_conf_user *user = obj;
02302    /* actual pointer contents of check_admin_arg is irrelevant */
02303 
02304    if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
02305       user->adminflags |= ADMINFLAG_KICKME;
02306    }
02307    return 0;
02308 }

static int user_set_muted_cb ( void *  obj,
void *  check_admin_arg,
int  flags 
) [static]

Definition at line 2321 of file app_meetme.c.

References ADMINFLAG_MUTED, ast_conf_user::adminflags, ast_test_flag64, CONFFLAG_ADMIN, and ast_conf_user::userflags.

Referenced by admin_exec(), and meetme_menu_admin_extended().

02322 {
02323    struct ast_conf_user *user = obj;
02324    /* actual pointer contents of check_admin_arg is irrelevant */
02325 
02326    if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
02327       user->adminflags |= ADMINFLAG_MUTED;
02328    }
02329    return 0;
02330 }

static int user_set_unmuted_cb ( void *  obj,
void *  check_admin_arg,
int  flags 
) [static]

Definition at line 2310 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ast_test_flag64, CONFFLAG_ADMIN, and ast_conf_user::userflags.

Referenced by admin_exec(), and meetme_menu_admin_extended().

02311 {
02312    struct ast_conf_user *user = obj;
02313    /* actual pointer contents of check_admin_arg is irrelevant */
02314 
02315    if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
02316       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
02317    }
02318    return 0;
02319 }

static int user_talk_voldown_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4764 of file app_meetme.c.

References tweak_talk_volume(), and VOL_DOWN.

Referenced by admin_exec().

04765 {
04766    struct ast_conf_user *user = obj;
04767    tweak_talk_volume(user, VOL_DOWN);
04768    return 0;
04769 }

static int user_talk_volup_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4757 of file app_meetme.c.

References tweak_talk_volume(), and VOL_UP.

Referenced by admin_exec().

04758 {
04759    struct ast_conf_user *user = obj;
04760    tweak_talk_volume(user, VOL_UP);
04761    return 0;
04762 }


Variable Documentation

const char* const app = "MeetMe" [static]

Definition at line 676 of file app_meetme.c.

const char* const app2 = "MeetMeCount" [static]

Definition at line 677 of file app_meetme.c.

const char* const app3 = "MeetMeAdmin" [static]

Definition at line 678 of file app_meetme.c.

const char* const app4 = "MeetMeChannelAdmin" [static]

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

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1885 of file app_meetme.c.

unsigned int conf_map[1024] = {0, } [static]

Definition at line 761 of file app_meetme.c.

Referenced by build_conf(), conf_exec(), and dispose_conf().

int earlyalert [static]

Definition at line 686 of file app_meetme.c.

int endalert [static]

Definition at line 687 of file app_meetme.c.

int extendby [static]

Definition at line 688 of file app_meetme.c.

int fuzzystart [static]

Definition at line 685 of file app_meetme.c.

const char 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 988 of file app_meetme.c.

Definition at line 964 of file app_meetme.c.

Referenced by ast_localtime_wakeup_monitor(), reload(), smdi_message_wait(), and write_cdr().

Initial value:

Definition at line 7636 of file app_meetme.c.

Initial value:
 {
   AST_DATA_ENTRY("asterisk/application/meetme/list", &meetme_data_provider),
}

Definition at line 7641 of file app_meetme.c.

Initial value:
 {
   .name = "MEETME_INFO",
   .read = acf_meetme_info,
}

Definition at line 7515 of file app_meetme.c.

int rt_log_members [static]

Log participant count to the RealTime backend

Definition at line 691 of file app_meetme.c.

int rt_schedule [static]

Definition at line 684 of file app_meetme.c.

struct { ... } sla [static]
const char sla_registrar[] = "SLA" [static]
struct ao2_container* sla_stations [static]
struct ao2_container* sla_trunks [static]
const char* const slastation_app = "SLAStation" [static]

Definition at line 680 of file app_meetme.c.

const char* const slatrunk_app = "SLATrunk" [static]

Definition at line 681 of file app_meetme.c.

pthread_t thread

Generated on 3 Apr 2014 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1