Tue Aug 20 16:34:42 2013

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"

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
struct  sla_trunk
struct  sla_trunk_ref
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, SLA_EVENT_RELOAD,
  SLA_EVENT_CHECK_RELOAD
}
 

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

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

Functions

static 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 AST_RWLIST_HEAD_STATIC (sla_trunks, sla_trunk)
static AST_RWLIST_HEAD_STATIC (sla_stations, sla_station)
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 destroy_station (struct sla_station *station)
static void destroy_trunk (struct sla_trunk *trunk)
static void * dial_trunk (void *data)
static int dispose_conf (struct ast_conference *conf)
 Decrement reference counts, as incremented by find_conf().
static 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, 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, 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 void sla_check_reload (void)
 Check if we can do a reload of SLA, and do it if we can.
static int sla_check_ringing_station (const struct sla_station *station)
 Check to see if this station is already ringing.
static int sla_check_station_delay (struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
 Calculate the ring delay for a given ringing trunk on a station.
static int sla_check_station_hold_access (const struct sla_trunk *trunk, const struct sla_station *station)
static int sla_check_timed_out_station (const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
 Check to see if dialing this station already timed out for this ringing trunk.
static struct sla_trunk_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_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 struct sla_stationsla_find_station (const char *name)
 Find an SLA station by name.
static struct sla_trunksla_find_trunk (const char *name)
 Find an SLA trunk by 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_load_config (int reload)
static int sla_process_timers (struct timespec *ts)
 Calculate the time until the next known event.
static void sla_queue_event (enum sla_event_type type)
static void sla_queue_event_conf (enum sla_event_type type, struct ast_channel *chan, struct ast_conference *conf)
 Queue a SLA event from the conference.
static void sla_queue_event_full (enum sla_event_type type, struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
static void sla_queue_event_nolock (enum sla_event_type type)
static int sla_ring_station (struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
 Ring a station.
static void sla_ring_stations (void)
 Ring stations based on current set of ringing trunks.
static char * sla_show_stations (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * sla_show_trunks (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static enum ast_device_state sla_state (const char *data)
static enum ast_device_state sla_state_to_devstate (enum sla_trunk_state state)
static int sla_station_exec (struct ast_channel *chan, const char *data)
static void sla_stop_ringing_station (struct sla_ringing_station *ringing_station, enum sla_station_hangup hangup)
static void sla_stop_ringing_trunk (struct sla_ringing_trunk *ringing_trunk)
static void * sla_thread (void *data)
static int sla_trunk_exec (struct ast_channel *chan, const char *data)
static const char * trunkstate2str (enum sla_trunk_state state)
static void tweak_listen_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_talk_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_volume (struct volume *vol, enum volume_action action)
static int unload_module (void)
static int user_add_provider_cb (void *obj, void *arg, int flags)
static int user_chan_cb (void *obj, void *args, int flags)
static int user_listen_voldown_cb (void *obj, void *unused, int flags)
static int user_listen_volup_cb (void *obj, void *unused, int flags)
static int user_max_cmp (void *obj, void *arg, int flags)
static int user_no_cmp (void *obj, void *arg, int flags)
static int user_reset_vol_cb (void *obj, void *unused, int flags)
static int user_set_kickme_cb (void *obj, void *check_admin_arg, int flags)
static int user_set_muted_cb (void *obj, void *check_admin_arg, int flags)
static int user_set_unmuted_cb (void *obj, void *check_admin_arg, int flags)
static int user_talk_voldown_cb (void *obj, void *unused, int flags)
static int user_talk_volup_cb (void *obj, void *unused, int flags)

Variables

static 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 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 7248 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 7265 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 6605 of file app_meetme.c.

06605      {
06606    SLA_TRUNK_OPT_MOH = (1 << 0),
06607 };

anonymous enum
Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 6609 of file app_meetme.c.

06609      {
06610    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
06611    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
06612 };

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

02295                 {
02296    MENU_DISABLED = 0,
02297    MENU_NORMAL,
02298    MENU_ADMIN,
02299    MENU_ADMIN_EXTENDED,
02300 };

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

SLA_EVENT_RELOAD 

A reload of configuration has been requested

SLA_EVENT_CHECK_RELOAD 

Poke the SLA thread so it can check if it can perform a reload

Definition at line 894 of file app_meetme.c.

00894                     {
00895    /*! A station has put the call on hold */
00896    SLA_EVENT_HOLD,
00897    /*! The state of a dial has changed */
00898    SLA_EVENT_DIAL_STATE,
00899    /*! The state of a ringing trunk has changed */
00900    SLA_EVENT_RINGING_TRUNK,
00901    /*! A reload of configuration has been requested */
00902    SLA_EVENT_RELOAD,
00903    /*! Poke the SLA thread so it can check if it can perform a reload */
00904    SLA_EVENT_CHECK_RELOAD,
00905 };

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

07178 {
07179    struct ast_conference *conf;
07180    char *parse;
07181    int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
07182    AST_DECLARE_APP_ARGS(args,
07183       AST_APP_ARG(keyword);
07184       AST_APP_ARG(confno);
07185    );
07186 
07187    if (ast_strlen_zero(data)) {
07188       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
07189       return -1;
07190    }
07191 
07192    parse = ast_strdupa(data);
07193    AST_STANDARD_APP_ARGS(args, parse);
07194 
07195    if (ast_strlen_zero(args.keyword)) {
07196       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
07197       return -1;
07198    }
07199 
07200    if (ast_strlen_zero(args.confno)) {
07201       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
07202       return -1;
07203    }
07204 
07205    AST_LIST_LOCK(&confs);
07206    AST_LIST_TRAVERSE(&confs, conf, list) {
07207       if (!strcmp(args.confno, conf->confno)) {
07208          result = acf_meetme_info_eval(args.keyword, conf);
07209          break;
07210       }
07211    }
07212    AST_LIST_UNLOCK(&confs);
07213 
07214    if (result > -1) {
07215       snprintf(buf, len, "%d", result);
07216    } else if (result == -1) {
07217       ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
07218       snprintf(buf, len, "0");
07219    } else if (result == -2) {
07220       ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno); 
07221       snprintf(buf, len, "0");
07222    }
07223 
07224    return 0;
07225 }

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

Definition at line 7159 of file app_meetme.c.

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

Referenced by acf_meetme_info().

07160 {
07161    if (!strcasecmp("lock", keyword)) {
07162       return conf->locked;
07163    } else if (!strcasecmp("parties", keyword)) {
07164       return conf->users;
07165    } else if (!strcasecmp("activity", keyword)) {
07166       time_t now;
07167       now = time(NULL);
07168       return (now - conf->start);
07169    } else if (!strcasecmp("dynamic", keyword)) {
07170       return conf->isdynamic;
07171    } else {
07172       return -1;
07173    }
07174 
07175 }

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

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

05035 {
05036    const char *actionid = astman_get_header(m, "ActionID");
05037    const char *conference = astman_get_header(m, "Conference");
05038    char idText[80] = "";
05039    struct ast_conference *cnf;
05040    struct ast_conf_user *user;
05041    struct ao2_iterator user_iter;
05042    int total = 0;
05043 
05044    if (!ast_strlen_zero(actionid))
05045       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
05046 
05047    if (AST_LIST_EMPTY(&confs)) {
05048       astman_send_error(s, m, "No active conferences.");
05049       return 0;
05050    }
05051 
05052    astman_send_listack(s, m, "Meetme user list will follow", "start");
05053 
05054    /* Find the right conference */
05055    AST_LIST_LOCK(&confs);
05056    AST_LIST_TRAVERSE(&confs, cnf, list) {
05057       /* If we ask for one particular, and this isn't it, skip it */
05058       if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
05059          continue;
05060 
05061       /* Show all the users */
05062       user_iter = ao2_iterator_init(cnf->usercontainer, 0);
05063       while ((user = ao2_iterator_next(&user_iter))) {
05064          total++;
05065          astman_append(s,
05066             "Event: MeetmeList\r\n"
05067             "%s"
05068             "Conference: %s\r\n"
05069             "UserNumber: %d\r\n"
05070             "CallerIDNum: %s\r\n"
05071             "CallerIDName: %s\r\n"
05072             "ConnectedLineNum: %s\r\n"
05073             "ConnectedLineName: %s\r\n"
05074             "Channel: %s\r\n"
05075             "Admin: %s\r\n"
05076             "Role: %s\r\n"
05077             "MarkedUser: %s\r\n"
05078             "Muted: %s\r\n"
05079             "Talking: %s\r\n"
05080             "\r\n",
05081             idText,
05082             cnf->confno,
05083             user->user_no,
05084             S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
05085             S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
05086             S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
05087             S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<no name>"),
05088             user->chan->name,
05089             ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
05090             ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
05091             ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
05092             user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
05093             user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
05094          ao2_ref(user, -1);
05095       }
05096       ao2_iterator_destroy(&user_iter);
05097    }
05098    AST_LIST_UNLOCK(&confs);
05099    /* Send final confirmation */
05100    astman_append(s,
05101    "Event: MeetmeListComplete\r\n"
05102    "EventList: Complete\r\n"
05103    "ListItems: %d\r\n"
05104    "%s"
05105    "\r\n", total, idText);
05106    return 0;
05107 }

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

Definition at line 5024 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

05025 {
05026    return meetmemute(s, m, 1);
05027 }

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

Definition at line 5029 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

05030 {
05031    return meetmemute(s, m, 0);
05032 }

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

The MeetMeadmin application.

MeetMeAdmin(confno, command, caller)

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

04756                                                                   {
04757    char *params;
04758    struct ast_conference *cnf;
04759    struct ast_conf_user *user = NULL;
04760    AST_DECLARE_APP_ARGS(args,
04761       AST_APP_ARG(confno);
04762       AST_APP_ARG(command);
04763       AST_APP_ARG(user);
04764    );
04765    int res = 0;
04766 
04767    if (ast_strlen_zero(data)) {
04768       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
04769       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04770       return -1;
04771    }
04772 
04773    params = ast_strdupa(data);
04774    AST_STANDARD_APP_ARGS(args, params);
04775 
04776    if (!args.command) {
04777       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
04778       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04779       return -1;
04780    }
04781 
04782    AST_LIST_LOCK(&confs);
04783    AST_LIST_TRAVERSE(&confs, cnf, list) {
04784       if (!strcmp(cnf->confno, args.confno))
04785          break;
04786    }
04787 
04788    if (!cnf) {
04789       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
04790       AST_LIST_UNLOCK(&confs);
04791       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
04792       return 0;
04793    }
04794 
04795    ast_atomic_fetchadd_int(&cnf->refcount, 1);
04796 
04797    if (args.user) {
04798       user = find_user(cnf, args.user);
04799       if (!user) {
04800          ast_log(LOG_NOTICE, "Specified User not found!\n");
04801          res = -2;
04802          goto usernotfound;
04803       }
04804    }
04805 
04806    switch (*args.command) {
04807    case 76: /* L: Lock */ 
04808       cnf->locked = 1;
04809       break;
04810    case 108: /* l: Unlock */ 
04811       cnf->locked = 0;
04812       break;
04813    case 75: /* K: kick all users */
04814       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_kickme_cb, NULL);
04815       break;
04816    case 101: /* e: Eject last user*/
04817    {
04818       int max_no = 0;
04819 
04820       /* If they passed in a user, disregard it */
04821       if (user) {
04822          ao2_ref(user, -1);
04823       }
04824 
04825       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
04826       user = ao2_find(cnf->usercontainer, &max_no, 0);
04827       if (!ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))
04828          user->adminflags |= ADMINFLAG_KICKME;
04829       else {
04830          res = -1;
04831          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
04832       }
04833       ao2_ref(user, -1);
04834       break;
04835    }
04836    case 77: /* M: Mute */ 
04837       user->adminflags |= ADMINFLAG_MUTED;
04838       break;
04839    case 78: /* N: Mute all (non-admin) users */
04840       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_muted_cb, &cnf);
04841       break;               
04842    case 109: /* m: Unmute */ 
04843       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04844       break;
04845    case 110: /* n: Unmute all users */
04846       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, NULL);
04847       break;
04848    case 107: /* k: Kick user */ 
04849       user->adminflags |= ADMINFLAG_KICKME;
04850       break;
04851    case 118: /* v: Lower all users listen volume */
04852       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_voldown_cb, NULL);
04853       break;
04854    case 86: /* V: Raise all users listen volume */
04855       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_volup_cb, NULL);
04856       break;
04857    case 115: /* s: Lower all users speaking volume */
04858       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_voldown_cb, NULL);
04859       break;
04860    case 83: /* S: Raise all users speaking volume */
04861       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_volup_cb, NULL);
04862       break;
04863    case 82: /* R: Reset all volume levels */
04864       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_reset_vol_cb, NULL);
04865       break;
04866    case 114: /* r: Reset user's volume level */
04867       reset_volumes(user);
04868       break;
04869    case 85: /* U: Raise user's listen volume */
04870       tweak_listen_volume(user, VOL_UP);
04871       break;
04872    case 117: /* u: Lower user's listen volume */
04873       tweak_listen_volume(user, VOL_DOWN);
04874       break;
04875    case 84: /* T: Raise user's talk volume */
04876       tweak_talk_volume(user, VOL_UP);
04877       break;
04878    case 116: /* t: Lower user's talk volume */
04879       tweak_talk_volume(user, VOL_DOWN);
04880       break;
04881    case 'E': /* E: Extend conference */
04882       if (rt_extend_conf(args.confno)) {
04883          res = -1;
04884       }
04885       break;
04886    }
04887 
04888    if (args.user) {
04889       /* decrement reference from find_user */
04890       ao2_ref(user, -1);
04891    }
04892 usernotfound:
04893    AST_LIST_UNLOCK(&confs);
04894 
04895    dispose_conf(cnf);
04896    pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
04897 
04898    return 0;
04899 }

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

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

02172 {
02173    struct announce_listitem *current;
02174    struct ast_conference *conf = data;
02175    int res;
02176    char filename[PATH_MAX] = "";
02177    AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
02178    AST_LIST_HEAD_INIT_NOLOCK(&local_list);
02179 
02180    while (!conf->announcethread_stop) {
02181       ast_mutex_lock(&conf->announcelistlock);
02182       if (conf->announcethread_stop) {
02183          ast_mutex_unlock(&conf->announcelistlock);
02184          break;
02185       }
02186       if (AST_LIST_EMPTY(&conf->announcelist))
02187          ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
02188 
02189       AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
02190       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
02191 
02192       ast_mutex_unlock(&conf->announcelistlock);
02193       if (conf->announcethread_stop) {
02194          break;
02195       }
02196 
02197       for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
02198          ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
02199          if (!ast_fileexists(current->namerecloc, NULL, NULL))
02200             continue;
02201          if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
02202             if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
02203                res = ast_waitstream(current->confchan, "");
02204             if (!res) {
02205                ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
02206                if (!ast_streamfile(current->confchan, filename, current->language))
02207                   ast_waitstream(current->confchan, "");
02208             }
02209          }
02210          if (current->announcetype == CONF_HASLEFT) {
02211             ast_filedelete(current->namerecloc, NULL);
02212          }
02213       }
02214    }
02215 
02216    /* thread marked to stop, clean up */
02217    while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
02218       ast_filedelete(current->namerecloc, NULL);
02219       ao2_ref(current, -1);
02220    }
02221    return NULL;
02222 }

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

Definition at line 5446 of file app_meetme.c.

References ast_answer(), and ast_indicate().

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

05447 {
05448    ast_answer(chan);
05449    ast_indicate(chan, -1);
05450 }

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 AST_RWLIST_HEAD_STATIC ( sla_trunks  ,
sla_trunk   
) [static]
static AST_RWLIST_HEAD_STATIC ( sla_stations  ,
sla_station   
) [static]
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 1202 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().

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

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

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

02225 {
02226    if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02227       return 1;
02228    }
02229 
02230    return (chan->_state == AST_STATE_UP);
02231 }

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

Definition at line 1005 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

Referenced by conf_play(), and conf_run().

01006 {
01007    int res;
01008    int x;
01009 
01010    while (len) {
01011       if (block) {
01012          x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
01013          res = ioctl(fd, DAHDI_IOMUX, &x);
01014       } else
01015          res = 0;
01016       if (res >= 0)
01017          res = write(fd, data, len);
01018       if (res < 1) {
01019          if (errno != EAGAIN) {
01020             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
01021             return -1;
01022          } else
01023             return 0;
01024       }
01025       len -= res;
01026       data += res;
01027    }
01028 
01029    return 0;
01030 }

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

The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command).

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

04903                                                                           {
04904    char *params;
04905    struct ast_conference *conf = NULL;
04906    struct ast_conf_user *user = NULL;
04907    AST_DECLARE_APP_ARGS(args,
04908       AST_APP_ARG(channel);
04909       AST_APP_ARG(command);
04910    );
04911 
04912    if (ast_strlen_zero(data)) {
04913       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
04914       return -1;
04915    }
04916    
04917    params = ast_strdupa(data);
04918    AST_STANDARD_APP_ARGS(args, params);
04919 
04920    if (!args.channel) {
04921       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
04922       return -1;
04923    }
04924 
04925    if (!args.command) {
04926       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
04927       return -1;
04928    }
04929 
04930    AST_LIST_LOCK(&confs);
04931    AST_LIST_TRAVERSE(&confs, conf, list) {
04932       if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
04933          break;
04934       }
04935    }
04936    
04937    if (!user) {
04938       ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
04939       AST_LIST_UNLOCK(&confs);
04940       return 0;
04941    }
04942    
04943    /* perform the specified action */
04944    switch (*args.command) {
04945       case 77: /* M: Mute */ 
04946          user->adminflags |= ADMINFLAG_MUTED;
04947          break;
04948       case 109: /* m: Unmute */ 
04949          user->adminflags &= ~ADMINFLAG_MUTED;
04950          break;
04951       case 107: /* k: Kick user */ 
04952          user->adminflags |= ADMINFLAG_KICKME;
04953          break;
04954       default: /* unknown command */
04955          ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
04956          break;
04957    }
04958    ao2_ref(user, -1);
04959    AST_LIST_UNLOCK(&confs);
04960    
04961    return 0;
04962 }

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

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

01313 {
01314    struct ast_conference *cnf;
01315    char *ret = NULL;
01316    int which = 0;
01317    int len = strlen(word);
01318 
01319    AST_LIST_LOCK(&confs);
01320    AST_LIST_TRAVERSE(&confs, cnf, list) {
01321       if (!strncmp(word, cnf->confno, len) && ++which > state) {
01322          /* dup before releasing the lock */
01323          ret = ast_strdup(cnf->confno);
01324          break;
01325       }
01326    }
01327    AST_LIST_UNLOCK(&confs);
01328    return ret;
01329 }

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

Definition at line 1401 of file app_meetme.c.

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

Referenced by meetme_show_cmd().

01402 {
01403    int len;
01404 
01405    if (pos == 2) {
01406       len = strlen(word);
01407       if (!strncasecmp(word, STR_CONCISE, len)) {
01408          if (state == 0) {
01409             return ast_strdup(STR_CONCISE);
01410          }
01411          --state;
01412       }
01413 
01414       return complete_confno(word, state);
01415    }
01416    if (pos == 3 && state == 0) {
01417       char *saved = NULL;
01418       char *myline;
01419       char *confno;
01420 
01421       /* Extract the confno from the command line. */
01422       myline = ast_strdupa(line);
01423       strtok_r(myline, " ", &saved);
01424       strtok_r(NULL, " ", &saved);
01425       confno = strtok_r(NULL, " ", &saved);
01426 
01427       if (!strcasecmp(confno, STR_CONCISE)) {
01428          /* There is nothing valid in this position now. */
01429          return NULL;
01430       }
01431 
01432       len = strlen(word);
01433       if (!strncasecmp(word, STR_CONCISE, len)) {
01434          return ast_strdup(STR_CONCISE);
01435       }
01436    }
01437    return NULL;
01438 }

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

Definition at line 1393 of file app_meetme.c.

References complete_confno().

Referenced by meetme_lock_cmd().

01394 {
01395    if (pos == 2) {
01396       return complete_confno(word, state);
01397    }
01398    return NULL;
01399 }

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

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

01354 {
01355    if (pos == 2) {
01356       return complete_confno(word, state);
01357    }
01358    if (pos == 3) {
01359       int len = strlen(word);
01360       char *ret = NULL;
01361       char *saved = NULL;
01362       char *myline;
01363       char *confno;
01364       struct ast_conference *cnf;
01365 
01366       if (!strncasecmp(word, "all", len)) {
01367          if (state == 0) {
01368             return ast_strdup("all");
01369          }
01370          --state;
01371       }
01372 
01373       /* Extract the confno from the command line. */
01374       myline = ast_strdupa(line);
01375       strtok_r(myline, " ", &saved);
01376       strtok_r(NULL, " ", &saved);
01377       confno = strtok_r(NULL, " ", &saved);
01378 
01379       AST_LIST_LOCK(&confs);
01380       AST_LIST_TRAVERSE(&confs, cnf, list) {
01381          if (!strcmp(confno, cnf->confno)) {
01382             ret = complete_userno(cnf, word, state);
01383             break;
01384          }
01385       }
01386       AST_LIST_UNLOCK(&confs);
01387 
01388       return ret;
01389    }
01390    return NULL;
01391 }

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

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

01332 {
01333    char usrno[50];
01334    struct ao2_iterator iter;
01335    struct ast_conf_user *usr;
01336    char *ret = NULL;
01337    int which = 0;
01338    int len = strlen(word);
01339 
01340    iter = ao2_iterator_init(cnf->usercontainer, 0);
01341    for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) {
01342       snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
01343       if (!strncmp(word, usrno, len) && ++which > state) {
01344          ao2_ref(usr, -1);
01345          ret = ast_strdup(usrno);
01346          break;
01347       }
01348    }
01349    ao2_iterator_destroy(&iter);
01350    return ret;
01351 }

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

The meetme() application.

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

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

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

Definition at line 1870 of file app_meetme.c.

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

Referenced by conf_run().

01871 {
01872    int x;
01873 
01874    /* read any frames that may be waiting on the channel
01875       and throw them away
01876    */
01877    if (chan) {
01878       struct ast_frame *f;
01879 
01880       /* when no frames are available, this will wait
01881          for 1 millisecond maximum
01882       */
01883       while (ast_waitfor(chan, 1) > 0) {
01884          f = ast_read(chan);
01885          if (f)
01886             ast_frfree(f);
01887          else /* channel was hung up or something else happened */
01888             break;
01889       }
01890    }
01891 
01892    /* flush any data sitting in the pseudo channel */
01893    x = DAHDI_FLUSH_ALL;
01894    if (ioctl(fd, DAHDI_FLUSH, &x))
01895       ast_log(LOG_WARNING, "Error flushing channel\n");
01896 
01897 }

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

01903 {
01904    int x;
01905    struct announce_listitem *item;
01906    
01907    AST_LIST_REMOVE(&confs, conf, list);
01908    manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01909 
01910    if (conf->recording == MEETME_RECORD_ACTIVE) {
01911       conf->recording = MEETME_RECORD_TERMINATE;
01912       AST_LIST_UNLOCK(&confs);
01913       while (1) {
01914          usleep(1);
01915          AST_LIST_LOCK(&confs);
01916          if (conf->recording == MEETME_RECORD_OFF)
01917             break;
01918          AST_LIST_UNLOCK(&confs);
01919       }
01920    }
01921 
01922    for (x = 0; x < AST_FRAME_BITS; x++) {
01923       if (conf->transframe[x])
01924          ast_frfree(conf->transframe[x]);
01925       if (conf->transpath[x])
01926          ast_translator_free_path(conf->transpath[x]);
01927    }
01928    if (conf->announcethread != AST_PTHREADT_NULL) {
01929       ast_mutex_lock(&conf->announcelistlock);
01930       conf->announcethread_stop = 1;
01931       ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01932       ast_cond_signal(&conf->announcelist_addition);
01933       ast_mutex_unlock(&conf->announcelistlock);
01934       pthread_join(conf->announcethread, NULL);
01935    
01936       while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01937          ast_filedelete(item->namerecloc, NULL);
01938          ao2_ref(item, -1);
01939       }
01940       ast_mutex_destroy(&conf->announcelistlock);
01941    }
01942 
01943    if (conf->origframe)
01944       ast_frfree(conf->origframe);
01945    if (conf->lchan)
01946       ast_hangup(conf->lchan);
01947    if (conf->chan)
01948       ast_hangup(conf->chan);
01949    if (conf->fd >= 0)
01950       close(conf->fd);
01951    if (conf->recordingfilename) {
01952       ast_free(conf->recordingfilename);
01953    }
01954    if (conf->usercontainer) {
01955       ao2_ref(conf->usercontainer, -1);
01956    }
01957    if (conf->recordingformat) {
01958       ast_free(conf->recordingformat);
01959    }
01960    ast_mutex_destroy(&conf->playlock);
01961    ast_mutex_destroy(&conf->listenlock);
01962    ast_mutex_destroy(&conf->recordthreadlock);
01963    ast_mutex_destroy(&conf->announcethreadlock);
01964    ast_free(conf);
01965 
01966    return 0;
01967 }

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

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

01124 {
01125    unsigned char *data;
01126    int len;
01127    int res = -1;
01128 
01129    ast_test_suite_event_notify("CONFPLAY", "Channel: %s\r\n"
01130                            "Conference: %s\r\n"
01131                            "Marked: %d",
01132                            chan->name,
01133                            conf->confno,
01134                            conf->markedusers);
01135 
01136    if (!ast_check_hangup(chan))
01137       res = ast_autoservice_start(chan);
01138 
01139    AST_LIST_LOCK(&confs);
01140 
01141    switch(sound) {
01142    case ENTER:
01143       data = enter;
01144       len = sizeof(enter);
01145       break;
01146    case LEAVE:
01147       data = leave;
01148       len = sizeof(leave);
01149       break;
01150    default:
01151       data = NULL;
01152       len = 0;
01153    }
01154    if (data) {
01155       careful_write(conf->fd, data, len, 1);
01156    }
01157 
01158    AST_LIST_UNLOCK(&confs);
01159 
01160    if (!res) 
01161       ast_autoservice_stop(chan);
01162 }

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

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

01971 {
01972    struct ast_conf_user *user;
01973    struct ao2_iterator user_iter;
01974 
01975    user_iter = ao2_iterator_init(conf->usercontainer, 0);
01976    while ((user = ao2_iterator_next(&user_iter))) {
01977       if (user == sender) {
01978          ao2_ref(user, -1);
01979          continue;
01980       }
01981       if (ast_write(user->chan, f) < 0)
01982          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01983       ao2_ref(user, -1);
01984    }
01985    ao2_iterator_destroy(&user_iter);
01986 }

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

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

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

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

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

02142 {
02143    char *original_moh;
02144 
02145    ast_channel_lock(chan);
02146    original_moh = ast_strdupa(chan->musicclass);
02147    ast_string_field_set(chan, musicclass, musicclass);
02148    ast_channel_unlock(chan);
02149 
02150    ast_moh_start(chan, original_moh, NULL);
02151 
02152    ast_channel_lock(chan);
02153    ast_string_field_set(chan, musicclass, original_moh);
02154    ast_channel_unlock(chan);
02155 }

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

The MeetmeCount application.

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

04324 {
04325    int res = 0;
04326    struct ast_conference *conf;
04327    int count;
04328    char *localdata;
04329    char val[80] = "0"; 
04330    AST_DECLARE_APP_ARGS(args,
04331       AST_APP_ARG(confno);
04332       AST_APP_ARG(varname);
04333    );
04334 
04335    if (ast_strlen_zero(data)) {
04336       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
04337       return -1;
04338    }
04339    
04340    localdata = ast_strdupa(data);
04341 
04342    AST_STANDARD_APP_ARGS(args, localdata);
04343    
04344    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
04345 
04346    if (conf) {
04347       count = conf->users;
04348       dispose_conf(conf);
04349       conf = NULL;
04350    } else
04351       count = 0;
04352 
04353    if (!ast_strlen_zero(args.varname)) {
04354       /* have var so load it and exit */
04355       snprintf(val, sizeof(val), "%d", count);
04356       pbx_builtin_setvar_helper(chan, args.varname, val);
04357    } else {
04358       if (chan->_state != AST_STATE_UP) {
04359          ast_answer(chan);
04360       }
04361       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
04362    }
04363 
04364    return res;
04365 }

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

Definition at line 6572 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station().

06573 {
06574    struct sla_trunk_ref *trunk_ref;
06575 
06576    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
06577       return NULL;
06578 
06579    trunk_ref->trunk = trunk;
06580 
06581    return trunk_ref;
06582 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 6780 of file app_meetme.c.

References ast_context_remove_extension(), ast_free, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_MAX_APP, AST_MAX_EXTENSION, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_string_field_free_memory, ast_strlen_zero(), exten, PRIORITY_HINT, and sla_registrar.

Referenced by sla_build_station(), and sla_destroy().

06781 {
06782    struct sla_trunk_ref *trunk_ref;
06783 
06784    if (!ast_strlen_zero(station->autocontext)) {
06785       AST_RWLIST_RDLOCK(&sla_trunks);
06786       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06787          char exten[AST_MAX_EXTENSION];
06788          char hint[AST_MAX_APP];
06789          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06790          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06791          ast_context_remove_extension(station->autocontext, exten, 
06792             1, sla_registrar);
06793          ast_context_remove_extension(station->autocontext, hint, 
06794             PRIORITY_HINT, sla_registrar);
06795       }
06796       AST_RWLIST_UNLOCK(&sla_trunks);
06797    }
06798 
06799    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
06800       ast_free(trunk_ref);
06801 
06802    ast_string_field_free_memory(station);
06803    ast_free(station);
06804 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 6766 of file app_meetme.c.

References ast_context_remove_extension(), ast_free, AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, ast_strlen_zero(), and sla_registrar.

Referenced by sla_build_trunk(), and sla_destroy().

06767 {
06768    struct sla_station_ref *station_ref;
06769 
06770    if (!ast_strlen_zero(trunk->autocontext))
06771       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
06772 
06773    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
06774       ast_free(station_ref);
06775 
06776    ast_string_field_free_memory(trunk);
06777    ast_free(trunk);
06778 }

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

Definition at line 6262 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, sla, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, dial_trunk_args::station, and dial_trunk_args::trunk_ref.

Referenced by sla_station_exec().

06263 {
06264    struct dial_trunk_args *args = data;
06265    struct ast_dial *dial;
06266    char *tech, *tech_data;
06267    enum ast_dial_result dial_res;
06268    char conf_name[MAX_CONFNUM];
06269    struct ast_conference *conf;
06270    struct ast_flags64 conf_flags = { 0 };
06271    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
06272    int caller_is_saved;
06273    struct ast_party_caller caller;
06274    int last_state = 0;
06275    int current_state = 0;
06276 
06277    if (!(dial = ast_dial_create())) {
06278       ast_mutex_lock(args->cond_lock);
06279       ast_cond_signal(args->cond);
06280       ast_mutex_unlock(args->cond_lock);
06281       return NULL;
06282    }
06283 
06284    tech_data = ast_strdupa(trunk_ref->trunk->device);
06285    tech = strsep(&tech_data, "/");
06286    if (ast_dial_append(dial, tech, tech_data) == -1) {
06287       ast_mutex_lock(args->cond_lock);
06288       ast_cond_signal(args->cond);
06289       ast_mutex_unlock(args->cond_lock);
06290       ast_dial_destroy(dial);
06291       return NULL;
06292    }
06293 
06294    /* Do we need to save of the caller ID data? */
06295    caller_is_saved = 0;
06296    if (!sla.attempt_callerid) {
06297       caller_is_saved = 1;
06298       caller = trunk_ref->chan->caller;
06299       ast_party_caller_init(&trunk_ref->chan->caller);
06300    }
06301 
06302    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
06303 
06304    /* Restore saved caller ID */
06305    if (caller_is_saved) {
06306       ast_party_caller_free(&trunk_ref->chan->caller);
06307       trunk_ref->chan->caller = caller;
06308    }
06309 
06310    if (dial_res != AST_DIAL_RESULT_TRYING) {
06311       ast_mutex_lock(args->cond_lock);
06312       ast_cond_signal(args->cond);
06313       ast_mutex_unlock(args->cond_lock);
06314       ast_dial_destroy(dial);
06315       return NULL;
06316    }
06317 
06318    for (;;) {
06319       unsigned int done = 0;
06320       switch ((dial_res = ast_dial_state(dial))) {
06321       case AST_DIAL_RESULT_ANSWERED:
06322          trunk_ref->trunk->chan = ast_dial_answered(dial);
06323       case AST_DIAL_RESULT_HANGUP:
06324       case AST_DIAL_RESULT_INVALID:
06325       case AST_DIAL_RESULT_FAILED:
06326       case AST_DIAL_RESULT_TIMEOUT:
06327       case AST_DIAL_RESULT_UNANSWERED:
06328          done = 1;
06329          break;
06330       case AST_DIAL_RESULT_TRYING:
06331          current_state = AST_CONTROL_PROGRESS;
06332          break;
06333       case AST_DIAL_RESULT_RINGING:
06334       case AST_DIAL_RESULT_PROGRESS:
06335       case AST_DIAL_RESULT_PROCEEDING:
06336          current_state = AST_CONTROL_RINGING;
06337          break;
06338       }
06339       if (done)
06340          break;
06341 
06342       /* check that SLA station that originated trunk call is still alive */
06343       if (args->station && ast_device_state(args->station->device) == AST_DEVICE_NOT_INUSE) {
06344          ast_debug(3, "Originating station device %s no longer active\n", args->station->device);
06345          trunk_ref->trunk->chan = NULL;
06346          break;
06347       }
06348 
06349       /* If trunk line state changed, send indication back to originating SLA Station channel */
06350       if (current_state != last_state) {
06351          ast_debug(3, "Indicating State Change %d to channel %s\n", current_state, trunk_ref->chan->name);
06352          ast_indicate(trunk_ref->chan, current_state);
06353          last_state = current_state;
06354       }
06355 
06356       /* avoid tight loop... sleep for 1/10th second */
06357       ast_safe_sleep(trunk_ref->chan, 100);
06358    }
06359 
06360    if (!trunk_ref->trunk->chan) {
06361       ast_mutex_lock(args->cond_lock);
06362       ast_cond_signal(args->cond);
06363       ast_mutex_unlock(args->cond_lock);
06364       ast_dial_join(dial);
06365       ast_dial_destroy(dial);
06366       return NULL;
06367    }
06368 
06369    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
06370    ast_set_flag64(&conf_flags, 
06371       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
06372       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
06373    conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan, NULL);
06374 
06375    ast_mutex_lock(args->cond_lock);
06376    ast_cond_signal(args->cond);
06377    ast_mutex_unlock(args->cond_lock);
06378 
06379    if (conf) {
06380       conf_run(trunk_ref->trunk->chan, conf, &conf_flags, NULL);
06381       dispose_conf(conf);
06382       conf = NULL;
06383    }
06384 
06385    /* If the trunk is going away, it is definitely now IDLE. */
06386    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06387 
06388    trunk_ref->trunk->chan = NULL;
06389    trunk_ref->trunk->on_hold = 0;
06390 
06391    ast_dial_join(dial);
06392    ast_dial_destroy(dial);
06393 
06394    return NULL;
06395 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Decrement reference counts, as incremented by find_conf().

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

02061 {
02062    int res = 0;
02063    int confno_int = 0;
02064 
02065    AST_LIST_LOCK(&confs);
02066    if (ast_atomic_dec_and_test(&conf->refcount)) {
02067       /* Take the conference room number out of an inuse state */
02068       if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
02069          conf_map[confno_int] = 0;
02070       }
02071       conf_free(conf);
02072       res = 1;
02073    }
02074    AST_LIST_UNLOCK(&confs);
02075 
02076    return res;
02077 }

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

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

05116 {
05117    char *slash;
05118    if (ast_strlen_zero(filename)) {
05119       ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
05120    } else if (filename[0] != '/') {
05121       snprintf(buffer, PATH_MAX, "%s/meetme/%s", ast_config_AST_SPOOL_DIR, filename);
05122    } else {
05123       ast_copy_string(buffer, filename, PATH_MAX);
05124    }
05125 
05126    slash = buffer;
05127    if ((slash = strrchr(slash, '/'))) {
05128       *slash = '\0';
05129       ast_mkdir(buffer, 0777);
05130       *slash = '/';
05131    }
05132 }

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

04221 {
04222    struct ast_config *cfg;
04223    struct ast_variable *var;
04224    struct ast_flags config_flags = { 0 };
04225    struct ast_conference *cnf;
04226 
04227    AST_DECLARE_APP_ARGS(args,
04228       AST_APP_ARG(confno);
04229       AST_APP_ARG(pin);
04230       AST_APP_ARG(pinadmin);
04231    );
04232 
04233    /* Check first in the conference list */
04234    ast_debug(1, "The requested confno is '%s'?\n", confno);
04235    AST_LIST_LOCK(&confs);
04236    AST_LIST_TRAVERSE(&confs, cnf, list) {
04237       ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
04238       if (!strcmp(confno, cnf->confno)) 
04239          break;
04240    }
04241    if (cnf) {
04242       cnf->refcount += refcount;
04243    }
04244    AST_LIST_UNLOCK(&confs);
04245 
04246    if (!cnf) {
04247       if (dynamic) {
04248          /* No need to parse meetme.conf */
04249          ast_debug(1, "Building dynamic conference '%s'\n", confno);
04250          if (dynamic_pin) {
04251             if (dynamic_pin[0] == 'q') {
04252                /* Query the user to enter a PIN */
04253                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
04254                   return NULL;
04255             }
04256             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan, NULL);
04257          } else {
04258             cnf = build_conf(confno, "", "", make, dynamic, refcount, chan, NULL);
04259          }
04260       } else {
04261          /* Check the config */
04262          cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
04263          if (!cfg) {
04264             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
04265             return NULL;
04266          } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04267             ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
04268             return NULL;
04269          }
04270 
04271          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
04272             char parse[MAX_SETTINGS];
04273 
04274             if (strcasecmp(var->name, "conf"))
04275                continue;
04276 
04277             ast_copy_string(parse, var->value, sizeof(parse));
04278 
04279             AST_STANDARD_APP_ARGS(args, parse);
04280             ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
04281             if (!strcasecmp(args.confno, confno)) {
04282                /* Bingo it's a valid conference */
04283                cnf = build_conf(args.confno,
04284                      S_OR(args.pin, ""),
04285                      S_OR(args.pinadmin, ""),
04286                      make, dynamic, refcount, chan, NULL);
04287                break;
04288             }
04289          }
04290          if (!var) {
04291             ast_debug(1, "%s isn't a valid conference\n", confno);
04292          }
04293          ast_config_destroy(cfg);
04294       }
04295    } else if (dynamic_pin) {
04296       /* Correct for the user selecting 'D' instead of 'd' to have
04297          someone join into a conference that has already been created
04298          with a pin. */
04299       if (dynamic_pin[0] == 'q') {
04300          dynamic_pin[0] = '\0';
04301       }
04302    }
04303 
04304    if (cnf) {
04305       if (confflags && !cnf->chan &&
04306           !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
04307           ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
04308          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
04309          ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
04310       }
04311       
04312       if (confflags && !cnf->chan &&
04313           ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
04314          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
04315          ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
04316       }
04317    }
04318 
04319    return cnf;
04320 }

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

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

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

Definition at line 4693 of file app_meetme.c.

References ao2_find, and ast_conference::usercontainer.

Referenced by admin_exec().

04694 {
04695    struct ast_conf_user *user = NULL;
04696    int cid;
04697 
04698    if (conf && callerident && sscanf(callerident, "%30d", &cid) == 1) {
04699       user = ao2_find(conf->usercontainer, &cid, 0);
04700       /* reference decremented later in admin_exec */
04701       return user;
04702    }
04703    return NULL;
04704 }

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

Definition at line 2157 of file app_meetme.c.

References CONF_HASJOIN, and CONF_HASLEFT.

Referenced by announce_thread().

02158 {
02159    switch (type) {
02160    case CONF_HASLEFT:
02161       return "conf-hasleft";
02162       break;
02163    case CONF_HASJOIN:
02164       return "conf-hasjoin";
02165       break;
02166    default:
02167       return "";
02168    }
02169 }

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

Definition at line 995 of file app_meetme.c.

Referenced by meetme_show_cmd().

00996 {
00997    if (x > 0)
00998       return "(talking)";
00999    else if (x < 0)
01000       return "(unmonitored)";
01001    else 
01002       return "(not talking)";
01003 }

static int load_config ( int  reload  )  [static]

Definition at line 7234 of file app_meetme.c.

References ast_log(), AST_PTHREADT_NULL, load_config_meetme(), LOG_NOTICE, sla, SLA_EVENT_RELOAD, sla_load_config(), and sla_queue_event().

Referenced by load_module(), and reload().

07235 {
07236    load_config_meetme();
07237 
07238    if (reload && sla.thread != AST_PTHREADT_NULL) {
07239       sla_queue_event(SLA_EVENT_RELOAD);
07240       ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
07241          "and will be completed when the system is idle.\n");
07242       return 0;
07243    }
07244    
07245    return sla_load_config(0);
07246 }

static void load_config_meetme ( void   )  [static]

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

05226 {
05227    struct ast_config *cfg;
05228    struct ast_flags config_flags = { 0 };
05229    const char *val;
05230 
05231    if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
05232       return;
05233    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
05234       ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
05235       return;
05236    }
05237 
05238    audio_buffers = DEFAULT_AUDIO_BUFFERS;
05239 
05240    /*  Scheduling support is off by default */
05241    rt_schedule = 0;
05242    fuzzystart = 0;
05243    earlyalert = 0;
05244    endalert = 0;
05245    extendby = 0;
05246 
05247    /*  Logging of participants defaults to ON for compatibility reasons */
05248    rt_log_members = 1;  
05249 
05250    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
05251       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
05252          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
05253          audio_buffers = DEFAULT_AUDIO_BUFFERS;
05254       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
05255          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
05256             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
05257          audio_buffers = DEFAULT_AUDIO_BUFFERS;
05258       }
05259       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
05260          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
05261    }
05262 
05263    if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
05264       rt_schedule = ast_true(val);
05265    if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
05266       rt_log_members = ast_true(val);
05267    if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
05268       if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
05269          ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
05270          fuzzystart = 0;
05271       } 
05272    }
05273    if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
05274       if ((sscanf(val, "%30d", &earlyalert) != 1)) {
05275          ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
05276          earlyalert = 0;
05277       } 
05278    }
05279    if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
05280       if ((sscanf(val, "%30d", &endalert) != 1)) {
05281          ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
05282          endalert = 0;
05283       } 
05284    }
05285    if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
05286       if ((sscanf(val, "%30d", &extendby) != 1)) {
05287          ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
05288          extendby = 0;
05289       } 
05290    }
05291 
05292    ast_config_destroy(cfg);
05293 }

static int load_module ( void   )  [static]

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

07460 {
07461    int res = 0;
07462 
07463    res |= load_config(0);
07464 
07465    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07466    res |= ast_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute);
07467    res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute);
07468    res |= ast_manager_register_xml("MeetmeList", EVENT_FLAG_REPORTING, action_meetmelist);
07469    res |= ast_register_application_xml(app4, channel_admin_exec);
07470    res |= ast_register_application_xml(app3, admin_exec);
07471    res |= ast_register_application_xml(app2, count_exec);
07472    res |= ast_register_application_xml(app, conf_exec);
07473    res |= ast_register_application_xml(slastation_app, sla_station_exec);
07474    res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
07475 
07476 #ifdef TEST_FRAMEWORK
07477    AST_TEST_REGISTER(test_meetme_data_provider);
07478 #endif
07479    ast_data_register_multiple(meetme_data_providers, ARRAY_LEN(meetme_data_providers));
07480 
07481    res |= ast_devstate_prov_add("Meetme", meetmestate);
07482    res |= ast_devstate_prov_add("SLA", sla_state);
07483 
07484    res |= ast_custom_function_register(&meetme_info_acf);
07485    ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
07486 
07487    return res;
07488 }

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

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

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

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

Definition at line 7323 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.

07325 {
07326    struct ast_conference *cnf;
07327    struct ast_data *data_meetme, *data_meetme_users;
07328 
07329    AST_LIST_LOCK(&confs);
07330    AST_LIST_TRAVERSE(&confs, cnf, list) {
07331       data_meetme = ast_data_add_node(data_root, "meetme");
07332       if (!data_meetme) {
07333          continue;
07334       }
07335 
07336       ast_data_add_structure(ast_conference, data_meetme, cnf);
07337 
07338       if (ao2_container_count(cnf->usercontainer)) {
07339          data_meetme_users = ast_data_add_node(data_meetme, "users");
07340          if (!data_meetme_users) {
07341             ast_data_remove_node(data_root, data_meetme);
07342             continue;
07343          }
07344 
07345          ao2_callback(cnf->usercontainer, OBJ_NODATA, user_add_provider_cb, data_meetme_users); 
07346       }
07347 
07348       if (!ast_data_search_match(search, data_meetme)) {
07349          ast_data_remove_node(data_root, data_meetme);
07350       }
07351    }
07352    AST_LIST_UNLOCK(&confs);
07353 
07354    return 0;
07355 }

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

Definition at line 1663 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.

01664 {
01665    switch (cmd) {
01666    case CLI_INIT:
01667       e->command = "meetme kick";
01668       e->usage =
01669          "Usage: meetme kick <confno> all|<userno>\n"
01670          "       Kick a conference or a user in a conference.\n";
01671       return NULL;
01672    case CLI_GENERATE:
01673       return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
01674    }
01675 
01676    if (a->argc != 4) {
01677       return CLI_SHOWUSAGE;
01678    }
01679 
01680    return meetme_cmd_helper(a);
01681 }

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

Definition at line 1643 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.

01644 {
01645    switch (cmd) {
01646    case CLI_INIT:
01647       e->command = "meetme {lock|unlock}";
01648       e->usage =
01649          "Usage: meetme lock|unlock <confno>\n"
01650          "       Lock or unlock a conference to new users.\n";
01651       return NULL;
01652    case CLI_GENERATE:
01653       return complete_meetmecmd_lock(a->word, a->pos, a->n);
01654    }
01655 
01656    if (a->argc != 3) {
01657       return CLI_SHOWUSAGE;
01658    }
01659 
01660    return meetme_cmd_helper(a);
01661 }

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,
struct dahdi_confinfo *  dahdic 
) [static]

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

02698 {
02699    switch (*menu_mode) {
02700    case MENU_DISABLED:
02701       break;
02702    case MENU_NORMAL:
02703       meetme_menu_normal(menu_mode, dtmf, conf, confflags, chan, user);
02704       break;
02705    case MENU_ADMIN:
02706       meetme_menu_admin(menu_mode, dtmf, conf, confflags, chan, user);
02707       /* Admin Menu is capable of branching into another menu, in which case it will reset dtmf and change the menu mode. */
02708       if (*menu_mode != MENU_ADMIN_EXTENDED || (*dtmf <= 0)) {
02709          break;
02710       }
02711    case MENU_ADMIN_EXTENDED:
02712       meetme_menu_admin_extended(menu_mode, dtmf, conf, confflags, chan, user, recordingtmp, dahdic);
02713       break;
02714    }
02715 }

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

02393 {
02394    switch(*dtmf) {
02395    case '1': /* Un/Mute */
02396       *menu_mode = MENU_DISABLED;
02397       /* for admin, change both admin and use flags */
02398       if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
02399          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02400       } else {
02401          user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02402       }
02403 
02404       if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02405          if (!ast_streamfile(chan, "conf-muted", chan->language)) {
02406             ast_waitstream(chan, "");
02407          }
02408       } else {
02409          if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
02410             ast_waitstream(chan, "");
02411          }
02412       }
02413       break;
02414 
02415    case '2': /* Un/Lock the Conference */
02416       *menu_mode = MENU_DISABLED;
02417       if (conf->locked) {
02418          conf->locked = 0;
02419          if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) {
02420             ast_waitstream(chan, "");
02421          }
02422       } else {
02423          conf->locked = 1;
02424          if (!ast_streamfile(chan, "conf-lockednow", chan->language)) {
02425             ast_waitstream(chan, "");
02426          }
02427       }
02428       break;
02429 
02430    case '3': /* Eject last user */
02431    {
02432       struct ast_conf_user *usr = NULL;
02433       int max_no = 0;
02434       ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
02435       *menu_mode = MENU_DISABLED;
02436       usr = ao2_find(conf->usercontainer, &max_no, 0);
02437       if ((usr->chan->name == chan->name) || ast_test_flag64(&usr->userflags, CONFFLAG_ADMIN)) {
02438          if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
02439             ast_waitstream(chan, "");
02440          }
02441       } else {
02442          usr->adminflags |= ADMINFLAG_KICKME;
02443       }
02444       ao2_ref(usr, -1);
02445       ast_stopstream(chan);
02446       break;
02447    }
02448 
02449    case '4':
02450       tweak_listen_volume(user, VOL_DOWN);
02451       break;
02452 
02453    case '5':
02454       /* Extend RT conference */
02455       if (rt_schedule) {
02456          if (!rt_extend_conf(conf->confno)) {
02457             if (!ast_streamfile(chan, "conf-extended", chan->language)) {
02458                ast_waitstream(chan, "");
02459             }
02460          } else {
02461             if (!ast_streamfile(chan, "conf-nonextended", chan->language)) {
02462                ast_waitstream(chan, "");
02463             }
02464          }
02465          ast_stopstream(chan);
02466       }
02467       *menu_mode = MENU_DISABLED;
02468       break;
02469 
02470    case '6':
02471       tweak_listen_volume(user, VOL_UP);
02472       break;
02473 
02474    case '7':
02475       tweak_talk_volume(user, VOL_DOWN);
02476       break;
02477 
02478    case '8':
02479       if (!ast_streamfile(chan, "conf-adminmenu-menu8", chan->language)) {
02480          /* 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. */
02481          *dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02482          ast_stopstream(chan);
02483       }
02484       *menu_mode = MENU_ADMIN_EXTENDED;
02485       break;
02486 
02487    case '9':
02488       tweak_talk_volume(user, VOL_UP);
02489       break;
02490    default:
02491       menu_mode = MENU_DISABLED;
02492       /* Play an error message! */
02493       if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
02494          ast_waitstream(chan, "");
02495       }
02496       break;
02497    }
02498 
02499 }

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,
struct dahdi_confinfo *  dahdic 
) [static]

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

02514 {
02515    int keepplaying;
02516    int playednamerec;
02517    int res;
02518    struct ao2_iterator user_iter;
02519    struct ast_conf_user *usr = NULL;
02520 
02521    switch(*dtmf) {
02522    case '1': /* *81 Roll call */
02523       keepplaying = 1;
02524       playednamerec = 0;
02525       if (conf->users == 1) {
02526          if (keepplaying && !ast_streamfile(chan, "conf-onlyperson", chan->language)) {
02527             res = ast_waitstream(chan, AST_DIGIT_ANY);
02528             ast_stopstream(chan);
02529             if (res > 0) {
02530                keepplaying = 0;
02531             }
02532          }
02533       } else if (conf->users == 2) {
02534          if (keepplaying && !ast_streamfile(chan, "conf-onlyone", chan->language)) {
02535             res = ast_waitstream(chan, AST_DIGIT_ANY);
02536             ast_stopstream(chan);
02537             if (res > 0) {
02538                keepplaying = 0;
02539             }
02540          }
02541       } else {
02542          if (keepplaying && !ast_streamfile(chan, "conf-thereare", chan->language)) {
02543             res = ast_waitstream(chan, AST_DIGIT_ANY);
02544             ast_stopstream(chan);
02545             if (res > 0) {
02546                keepplaying = 0;
02547             }
02548          }
02549          if (keepplaying) {
02550             res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
02551             ast_stopstream(chan);
02552             if (res > 0) {
02553                keepplaying = 0;
02554             }
02555          }
02556          if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
02557             res = ast_waitstream(chan, AST_DIGIT_ANY);
02558             ast_stopstream(chan);
02559             if (res > 0) {
02560                keepplaying = 0;
02561             }
02562          }
02563       }
02564       user_iter = ao2_iterator_init(conf->usercontainer, 0);
02565       while((usr = ao2_iterator_next(&user_iter))) {
02566          if (ast_fileexists(usr->namerecloc, NULL, NULL)) {
02567             if (keepplaying && !ast_streamfile(chan, usr->namerecloc, chan->language)) {
02568                res = ast_waitstream(chan, AST_DIGIT_ANY);
02569                ast_stopstream(chan);
02570                if (res > 0) {
02571                   keepplaying = 0;
02572                }
02573             }
02574             playednamerec = 1;
02575          }
02576          ao2_ref(usr, -1);
02577       }
02578       ao2_iterator_destroy(&user_iter);
02579       if (keepplaying && playednamerec && !ast_streamfile(chan, "conf-roll-callcomplete", chan->language)) {
02580          res = ast_waitstream(chan, AST_DIGIT_ANY);
02581          ast_stopstream(chan);
02582          if (res > 0) {
02583             keepplaying = 0;
02584          }
02585       }
02586 
02587       *menu_mode = MENU_DISABLED;
02588       break;
02589 
02590    case '2': /* *82 Eject all non-admins */
02591       if (conf->users == 1) {
02592          if(!ast_streamfile(chan, "conf-errormenu", chan->language)) {
02593             ast_waitstream(chan, "");
02594          }
02595       } else {
02596          ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_kickme_cb, &conf);
02597       }
02598       ast_stopstream(chan);
02599       *menu_mode = MENU_DISABLED;
02600       break;
02601 
02602    case '3': /* *83 (Admin) mute/unmute all non-admins */
02603       if(conf->gmuted) {
02604          conf->gmuted = 0;
02605          ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, &conf);
02606          if (!ast_streamfile(chan, "conf-now-unmuted", chan->language)) {
02607             ast_waitstream(chan, "");
02608          }
02609       } else {
02610          conf->gmuted = 1;
02611          ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_muted_cb, &conf);
02612          if (!ast_streamfile(chan, "conf-now-muted", chan->language)) {
02613             ast_waitstream(chan, "");
02614          }
02615       }
02616       ast_stopstream(chan);
02617       *menu_mode = MENU_DISABLED;
02618       break;
02619 
02620    case '4': /* *84 Record conference */
02621       if (conf->recording != MEETME_RECORD_ACTIVE) {
02622          ast_set_flag64(confflags, CONFFLAG_RECORDCONF);
02623          if (!conf->recordingfilename) {
02624             const char *var;
02625             ast_channel_lock(chan);
02626             if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
02627                conf->recordingfilename = ast_strdup(var);
02628             }
02629             if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
02630                conf->recordingformat = ast_strdup(var);
02631             }
02632             ast_channel_unlock(chan);
02633             if (!conf->recordingfilename) {
02634                snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
02635                conf->recordingfilename = ast_strdup(recordingtmp);
02636             }
02637             if (!conf->recordingformat) {
02638                conf->recordingformat = ast_strdup("wav");
02639             }
02640             ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
02641             conf->confno, conf->recordingfilename, conf->recordingformat);
02642          }
02643 
02644          ast_mutex_lock(&conf->recordthreadlock);
02645          if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, chan, "pseudo", NULL)))) {
02646             ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
02647             ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
02648             dahdic->chan = 0;
02649             dahdic->confno = conf->dahdiconf;
02650             dahdic->confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
02651             if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, dahdic)) {
02652                ast_log(LOG_WARNING, "Error starting listen channel\n");
02653                ast_hangup(conf->lchan);
02654                conf->lchan = NULL;
02655             } else {
02656                ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
02657             }
02658          }
02659          ast_mutex_unlock(&conf->recordthreadlock);
02660          if (!ast_streamfile(chan, "conf-now-recording", chan->language)) {
02661             ast_waitstream(chan, "");
02662          }
02663       }
02664 
02665       ast_stopstream(chan);
02666       *menu_mode = MENU_DISABLED;
02667       break;
02668 
02669    case '8': /* *88 Exit the menu and return to the conference... without an error message */
02670       ast_stopstream(chan);
02671       *menu_mode = MENU_DISABLED;
02672       break;
02673 
02674    default:
02675       if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
02676          ast_waitstream(chan, "");
02677       }
02678       ast_stopstream(chan);
02679       *menu_mode = MENU_DISABLED;
02680       break;
02681    }
02682 }

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

02313 {
02314    switch (*dtmf) {
02315    case '1': /* Un/Mute */
02316       *menu_mode = MENU_DISABLED;
02317 
02318       /* user can only toggle the self-muted state */
02319       user->adminflags ^= ADMINFLAG_SELFMUTED;
02320 
02321       /* they can't override the admin mute state */
02322       if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02323          if (!ast_streamfile(chan, "conf-muted", chan->language)) {
02324             ast_waitstream(chan, "");
02325          }
02326       } else {
02327          if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
02328             ast_waitstream(chan, "");
02329          }
02330       }
02331       break;
02332 
02333    case '2':
02334       *menu_mode = MENU_DISABLED;
02335       if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
02336          user->adminflags |= ADMINFLAG_T_REQUEST;
02337       }
02338 
02339       if (user->adminflags & ADMINFLAG_T_REQUEST) {
02340          if (!ast_streamfile(chan, "beep", chan->language)) {
02341             ast_waitstream(chan, "");
02342          }
02343       }
02344       break;
02345 
02346    case '4':
02347       tweak_listen_volume(user, VOL_DOWN);
02348       break;
02349    case '5':
02350       /* Extend RT conference */
02351       if (rt_schedule) {
02352          rt_extend_conf(conf->confno);
02353       }
02354       *menu_mode = MENU_DISABLED;
02355       break;
02356 
02357    case '6':
02358       tweak_listen_volume(user, VOL_UP);
02359       break;
02360 
02361    case '7':
02362       tweak_talk_volume(user, VOL_DOWN);
02363       break;
02364 
02365    case '8':
02366       *menu_mode = MENU_DISABLED;
02367       break;
02368 
02369    case '9':
02370       tweak_talk_volume(user, VOL_UP);
02371       break;
02372 
02373    default:
02374       *menu_mode = MENU_DISABLED;
02375       if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
02376          ast_waitstream(chan, "");
02377       }
02378       break;
02379    }
02380 }

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

Definition at line 1683 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.

01684 {
01685    switch (cmd) {
01686    case CLI_INIT:
01687       e->command = "meetme {mute|unmute}";
01688       e->usage =
01689          "Usage: meetme mute|unmute <confno> all|<userno>\n"
01690          "       Mute or unmute a conference or a user in a conference.\n";
01691       return NULL;
01692    case CLI_GENERATE:
01693       return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
01694    }
01695 
01696    if (a->argc != 4) {
01697       return CLI_SHOWUSAGE;
01698    }
01699 
01700    return meetme_cmd_helper(a);
01701 }

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

Definition at line 1440 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.

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

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

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

04965 {
04966    struct ast_conference *conf;
04967    struct ast_conf_user *user;
04968    const char *confid = astman_get_header(m, "Meetme");
04969    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
04970    int userno;
04971 
04972    if (ast_strlen_zero(confid)) {
04973       astman_send_error(s, m, "Meetme conference not specified");
04974       return 0;
04975    }
04976 
04977    if (ast_strlen_zero(userid)) {
04978       astman_send_error(s, m, "Meetme user number not specified");
04979       return 0;
04980    }
04981 
04982    userno = strtoul(userid, &userid, 10);
04983 
04984    if (*userid) {
04985       astman_send_error(s, m, "Invalid user number");
04986       return 0;
04987    }
04988 
04989    /* Look in the conference list */
04990    AST_LIST_LOCK(&confs);
04991    AST_LIST_TRAVERSE(&confs, conf, list) {
04992       if (!strcmp(confid, conf->confno))
04993          break;
04994    }
04995 
04996    if (!conf) {
04997       AST_LIST_UNLOCK(&confs);
04998       astman_send_error(s, m, "Meetme conference does not exist");
04999       return 0;
05000    }
05001 
05002    user = ao2_find(conf->usercontainer, &userno, 0);
05003 
05004    if (!user) {
05005       AST_LIST_UNLOCK(&confs);
05006       astman_send_error(s, m, "User number not found");
05007       return 0;
05008    }
05009 
05010    if (mute)
05011       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
05012    else
05013       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
05014 
05015    AST_LIST_UNLOCK(&confs);
05016 
05017    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);
05018 
05019    ao2_ref(user, -1);
05020    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
05021    return 0;
05022 }

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

Callback for devicestate providers.

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

05204 {
05205    struct ast_conference *conf;
05206 
05207    /* Find conference */
05208    AST_LIST_LOCK(&confs);
05209    AST_LIST_TRAVERSE(&confs, conf, list) {
05210       if (!strcmp(data, conf->confno))
05211          break;
05212    }
05213    AST_LIST_UNLOCK(&confs);
05214    if (!conf)
05215       return AST_DEVICE_INVALID;
05216 
05217 
05218    /* SKREP to fill */
05219    if (!conf->users)
05220       return AST_DEVICE_NOT_INUSE;
05221 
05222    return AST_DEVICE_INUSE;
05223 }

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

Definition at line 6584 of file app_meetme.c.

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

Referenced by sla_trunk_exec().

06585 {
06586    struct sla_ringing_trunk *ringing_trunk;
06587 
06588    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
06589       return NULL;
06590    
06591    ringing_trunk->trunk = trunk;
06592    ringing_trunk->ring_begin = ast_tvnow();
06593 
06594    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
06595 
06596    ast_mutex_lock(&sla.lock);
06597    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
06598    ast_mutex_unlock(&sla.lock);
06599 
06600    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06601 
06602    return ringing_trunk;
06603 }

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

Definition at line 5134 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.

05135 {
05136    struct ast_conference *cnf = args;
05137    struct ast_frame *f = NULL;
05138    int flags;
05139    struct ast_filestream *s = NULL;
05140    int res = 0;
05141    int x;
05142    const char *oldrecordingfilename = NULL;
05143    char filename_buffer[PATH_MAX];
05144 
05145    if (!cnf || !cnf->lchan) {
05146       pthread_exit(0);
05147    }
05148 
05149    filename_buffer[0] = '\0';
05150    filename_parse(cnf->recordingfilename, filename_buffer);
05151 
05152    ast_stopstream(cnf->lchan);
05153    flags = O_CREAT | O_TRUNC | O_WRONLY;
05154 
05155 
05156    cnf->recording = MEETME_RECORD_ACTIVE;
05157    while (ast_waitfor(cnf->lchan, -1) > -1) {
05158       if (cnf->recording == MEETME_RECORD_TERMINATE) {
05159          AST_LIST_LOCK(&confs);
05160          AST_LIST_UNLOCK(&confs);
05161          break;
05162       }
05163       if (!s && !(ast_strlen_zero(filename_buffer)) && (filename_buffer != oldrecordingfilename)) {
05164          s = ast_writefile(filename_buffer, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
05165          oldrecordingfilename = filename_buffer;
05166       }
05167       
05168       f = ast_read(cnf->lchan);
05169       if (!f) {
05170          res = -1;
05171          break;
05172       }
05173       if (f->frametype == AST_FRAME_VOICE) {
05174          ast_mutex_lock(&cnf->listenlock);
05175          for (x = 0; x < AST_FRAME_BITS; x++) {
05176             /* Free any translations that have occured */
05177             if (cnf->transframe[x]) {
05178                ast_frfree(cnf->transframe[x]);
05179                cnf->transframe[x] = NULL;
05180             }
05181          }
05182          if (cnf->origframe)
05183             ast_frfree(cnf->origframe);
05184          cnf->origframe = ast_frdup(f);
05185          ast_mutex_unlock(&cnf->listenlock);
05186          if (s)
05187             res = ast_writestream(s, f);
05188          if (res) {
05189             ast_frfree(f);
05190             break;
05191          }
05192       }
05193       ast_frfree(f);
05194    }
05195    cnf->recording = MEETME_RECORD_OFF;
05196    if (s)
05197       ast_closestream(s);
05198    
05199    pthread_exit(0);
05200 }

static int reload ( void   )  [static]

Definition at line 7490 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

07491 {
07492    ast_unload_realtime("meetme");
07493    return load_config(1);
07494 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

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

01116 {
01117    signed char zero_volume = 0;
01118 
01119    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
01120    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
01121 }

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

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

02080 {
02081    char currenttime[32];
02082    char endtime[32];
02083    struct timeval now;
02084    struct ast_tm tm;
02085    struct ast_variable *var, *orig_var;
02086    char bookid[51];
02087 
02088    if (!extendby) {
02089       return 0;
02090    }
02091 
02092    now = ast_tvnow();
02093 
02094    ast_localtime(&now, &tm, NULL);
02095    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02096 
02097    var = ast_load_realtime("meetme", "confno",
02098       confno, "startTime<= ", currenttime,
02099       "endtime>= ", currenttime, NULL);
02100 
02101    orig_var = var;
02102 
02103    /* Identify the specific RealTime conference */
02104    while (var) {
02105       if (!strcasecmp(var->name, "bookid")) {
02106          ast_copy_string(bookid, var->value, sizeof(bookid));
02107       }
02108       if (!strcasecmp(var->name, "endtime")) {
02109          ast_copy_string(endtime, var->value, sizeof(endtime));
02110       }
02111 
02112       var = var->next;
02113    }
02114    ast_variables_destroy(orig_var);
02115 
02116    ast_strptime(endtime, DATE_FORMAT, &tm);
02117    now = ast_mktime(&tm, NULL);
02118 
02119    now.tv_sec += extendby;
02120 
02121    ast_localtime(&now, &tm, NULL);
02122    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02123    strcat(currenttime, "0"); /* Seconds needs to be 00 */
02124 
02125    var = ast_load_realtime("meetme", "confno",
02126       confno, "startTime<= ", currenttime,
02127       "endtime>= ", currenttime, NULL);
02128 
02129    /* If there is no conflict with extending the conference, update the DB */
02130    if (!var) {
02131       ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
02132       ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
02133       return 0;
02134 
02135    }
02136 
02137    ast_variables_destroy(var);
02138    return -1;
02139 }

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

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

05453 {
05454    struct sla_station *station;
05455    struct sla_trunk_ref *trunk_ref;
05456    struct ast_str *conf_name = ast_str_create(16);
05457    struct ast_flags64 conf_flags = { 0 };
05458    struct ast_conference *conf;
05459 
05460    {
05461       struct run_station_args *args = data;
05462       station = args->station;
05463       trunk_ref = args->trunk_ref;
05464       ast_mutex_lock(args->cond_lock);
05465       ast_cond_signal(args->cond);
05466       ast_mutex_unlock(args->cond_lock);
05467       /* args is no longer valid here. */
05468    }
05469 
05470    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
05471    ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
05472    ast_set_flag64(&conf_flags, 
05473       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05474    answer_trunk_chan(trunk_ref->chan);
05475    conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan, NULL);
05476    if (conf) {
05477       conf_run(trunk_ref->chan, conf, &conf_flags, NULL);
05478       dispose_conf(conf);
05479       conf = NULL;
05480    }
05481    trunk_ref->chan = NULL;
05482    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05483       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05484       ast_str_append(&conf_name, 0, ",K");
05485       admin_exec(NULL, ast_str_buffer(conf_name));
05486       trunk_ref->trunk->hold_stations = 0;
05487       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05488    }
05489 
05490    ast_dial_join(station->dial);
05491    ast_dial_destroy(station->dial);
05492    station->dial = NULL;
05493    ast_free(conf_name);
05494 
05495    return NULL;
05496 }

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

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

02234 {
02235    ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking",
02236       "Channel: %s\r\n"
02237       "Uniqueid: %s\r\n"
02238       "Meetme: %s\r\n"
02239       "Usernum: %d\r\n"
02240       "Status: %s\r\n",
02241       chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
02242 }

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

Definition at line 1044 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

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

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

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

01033 {
01034    char gain_adjust;
01035 
01036    /* attempt to make the adjustment in the channel driver;
01037       if successful, don't adjust in the frame reading routine
01038    */
01039    gain_adjust = gain_map[volume + 5];
01040 
01041    return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
01042 }

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

References send_talking_event(), and ast_conf_user::talking.

Referenced by conf_run().

02245 {
02246    int last_talking = user->talking;
02247    if (last_talking == talking)
02248       return;
02249 
02250    user->talking = talking;
02251 
02252    if (monitor) {
02253       /* Check if talking state changed. Take care of -1 which means unmonitored */
02254       int was_talking = (last_talking > 0);
02255       int now_talking = (talking > 0);
02256       if (was_talking != now_talking) {
02257          send_talking_event(chan, conf, user, now_talking);
02258       }
02259    }
02260 }

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

Definition at line 6924 of file app_meetme.c.

References ast_atomic_fetchadd_int(), ast_free, AST_LIST_INSERT_TAIL, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdupa, create_trunk_ref(), LOG_ERROR, LOG_WARNING, name, sla_create_station_ref(), SLA_TRUNK_STATE_IDLE, value, and ast_variable::value.

Referenced by sla_build_station().

06925 {
06926    struct sla_trunk *trunk;
06927    struct sla_trunk_ref *trunk_ref;
06928    struct sla_station_ref *station_ref;
06929    char *trunk_name, *options, *cur;
06930 
06931    options = ast_strdupa(var->value);
06932    trunk_name = strsep(&options, ",");
06933    
06934    AST_RWLIST_RDLOCK(&sla_trunks);
06935    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
06936       if (!strcasecmp(trunk->name, trunk_name))
06937          break;
06938    }
06939 
06940    AST_RWLIST_UNLOCK(&sla_trunks);
06941    if (!trunk) {
06942       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
06943       return;
06944    }
06945    if (!(trunk_ref = create_trunk_ref(trunk)))
06946       return;
06947    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
06948 
06949    while ((cur = strsep(&options, ","))) {
06950       char *name, *value = cur;
06951       name = strsep(&value, "=");
06952       if (!strcasecmp(name, "ringtimeout")) {
06953          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
06954             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
06955                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06956             trunk_ref->ring_timeout = 0;
06957          }
06958       } else if (!strcasecmp(name, "ringdelay")) {
06959          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
06960             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
06961                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06962             trunk_ref->ring_delay = 0;
06963          }
06964       } else {
06965          ast_log(LOG_WARNING, "Invalid option '%s' for "
06966             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
06967       }
06968    }
06969 
06970    if (!(station_ref = sla_create_station_ref(station))) {
06971       ast_free(trunk_ref);
06972       return;
06973    }
06974    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
06975    AST_RWLIST_WRLOCK(&sla_trunks);
06976    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
06977    AST_RWLIST_UNLOCK(&sla_trunks);
06978    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
06979 }

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

Definition at line 6981 of file app_meetme.c.

References ast_add_extension2(), ast_calloc_with_stringfields, ast_context_find_or_create(), ast_free_ptr(), AST_LIST_TRAVERSE, ast_log(), AST_MAX_APP, AST_MAX_EXTENSION, AST_RWLIST_INSERT_TAIL, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), context, destroy_station(), exten, ast_variable::lineno, LOG_ERROR, LOG_WARNING, ast_variable::name, name, ast_variable::next, PRIORITY_HINT, sla_add_trunk_to_station(), SLA_CONFIG_FILE, SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, ast_variable::value, and var.

Referenced by sla_load_config().

06982 {
06983    struct sla_station *station;
06984    struct ast_variable *var;
06985    const char *dev;
06986 
06987    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06988       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
06989       return -1;
06990    }
06991 
06992    if (!(station = ast_calloc_with_stringfields(1, struct sla_station, 32))) {
06993       return -1;
06994    }
06995 
06996    ast_string_field_set(station, name, cat);
06997    ast_string_field_set(station, device, dev);
06998 
06999    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
07000       if (!strcasecmp(var->name, "trunk"))
07001          sla_add_trunk_to_station(station, var);
07002       else if (!strcasecmp(var->name, "autocontext"))
07003          ast_string_field_set(station, autocontext, var->value);
07004       else if (!strcasecmp(var->name, "ringtimeout")) {
07005          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
07006             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
07007                var->value, station->name);
07008             station->ring_timeout = 0;
07009          }
07010       } else if (!strcasecmp(var->name, "ringdelay")) {
07011          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
07012             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
07013                var->value, station->name);
07014             station->ring_delay = 0;
07015          }
07016       } else if (!strcasecmp(var->name, "hold")) {
07017          if (!strcasecmp(var->value, "private"))
07018             station->hold_access = SLA_HOLD_PRIVATE;
07019          else if (!strcasecmp(var->value, "open"))
07020             station->hold_access = SLA_HOLD_OPEN;
07021          else {
07022             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
07023                var->value, station->name);
07024          }
07025 
07026       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
07027          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
07028             var->name, var->lineno, SLA_CONFIG_FILE);
07029       }
07030    }
07031 
07032    if (!ast_strlen_zero(station->autocontext)) {
07033       struct ast_context *context;
07034       struct sla_trunk_ref *trunk_ref;
07035       context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
07036       if (!context) {
07037          ast_log(LOG_ERROR, "Failed to automatically find or create "
07038             "context '%s' for SLA!\n", station->autocontext);
07039          destroy_station(station);
07040          return -1;
07041       }
07042       /* The extension for when the handset goes off-hook.
07043        * exten => station1,1,SLAStation(station1) */
07044       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
07045          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
07046          ast_log(LOG_ERROR, "Failed to automatically create extension "
07047             "for trunk '%s'!\n", station->name);
07048          destroy_station(station);
07049          return -1;
07050       }
07051       AST_RWLIST_RDLOCK(&sla_trunks);
07052       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
07053          char exten[AST_MAX_EXTENSION];
07054          char hint[AST_MAX_APP];
07055          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
07056          snprintf(hint, sizeof(hint), "SLA:%s", exten);
07057          /* Extension for this line button 
07058           * exten => station1_line1,1,SLAStation(station1_line1) */
07059          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
07060             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
07061             ast_log(LOG_ERROR, "Failed to automatically create extension "
07062                "for trunk '%s'!\n", station->name);
07063             destroy_station(station);
07064             return -1;
07065          }
07066          /* Hint for this line button 
07067           * exten => station1_line1,hint,SLA:station1_line1 */
07068          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
07069             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
07070             ast_log(LOG_ERROR, "Failed to automatically create hint "
07071                "for trunk '%s'!\n", station->name);
07072             destroy_station(station);
07073             return -1;
07074          }
07075       }
07076       AST_RWLIST_UNLOCK(&sla_trunks);
07077    }
07078 
07079    AST_RWLIST_WRLOCK(&sla_stations);
07080    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
07081    AST_RWLIST_UNLOCK(&sla_stations);
07082 
07083    return 0;
07084 }

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

Definition at line 6849 of file app_meetme.c.

References ast_add_extension2(), ast_calloc_with_stringfields, ast_context_find_or_create(), ast_false(), ast_free_ptr(), ast_log(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), context, destroy_trunk(), ast_variable::lineno, LOG_ERROR, LOG_WARNING, ast_variable::name, name, ast_variable::next, sla_check_device(), SLA_CONFIG_FILE, SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, ast_variable::value, and var.

Referenced by sla_load_config().

06850 {
06851    struct sla_trunk *trunk;
06852    struct ast_variable *var;
06853    const char *dev;
06854 
06855    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06856       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
06857       return -1;
06858    }
06859 
06860    if (sla_check_device(dev)) {
06861       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
06862          cat, dev);
06863       return -1;
06864    }
06865 
06866    if (!(trunk = ast_calloc_with_stringfields(1, struct sla_trunk, 32))) {
06867       return -1;
06868    }
06869 
06870    ast_string_field_set(trunk, name, cat);
06871    ast_string_field_set(trunk, device, dev);
06872 
06873    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06874       if (!strcasecmp(var->name, "autocontext"))
06875          ast_string_field_set(trunk, autocontext, var->value);
06876       else if (!strcasecmp(var->name, "ringtimeout")) {
06877          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
06878             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
06879                var->value, trunk->name);
06880             trunk->ring_timeout = 0;
06881          }
06882       } else if (!strcasecmp(var->name, "barge"))
06883          trunk->barge_disabled = ast_false(var->value);
06884       else if (!strcasecmp(var->name, "hold")) {
06885          if (!strcasecmp(var->value, "private"))
06886             trunk->hold_access = SLA_HOLD_PRIVATE;
06887          else if (!strcasecmp(var->value, "open"))
06888             trunk->hold_access = SLA_HOLD_OPEN;
06889          else {
06890             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
06891                var->value, trunk->name);
06892          }
06893       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06894          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06895             var->name, var->lineno, SLA_CONFIG_FILE);
06896       }
06897    }
06898 
06899    if (!ast_strlen_zero(trunk->autocontext)) {
06900       struct ast_context *context;
06901       context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
06902       if (!context) {
06903          ast_log(LOG_ERROR, "Failed to automatically find or create "
06904             "context '%s' for SLA!\n", trunk->autocontext);
06905          destroy_trunk(trunk);
06906          return -1;
06907       }
06908       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
06909          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
06910          ast_log(LOG_ERROR, "Failed to automatically create extension "
06911             "for trunk '%s'!\n", trunk->name);
06912          destroy_trunk(trunk);
06913          return -1;
06914       }
06915    }
06916 
06917    AST_RWLIST_WRLOCK(&sla_trunks);
06918    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
06919    AST_RWLIST_UNLOCK(&sla_trunks);
06920 
06921    return 0;
06922 }

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

References AST_LIST_TRAVERSE, sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), and sla_choose_ringing_trunk().

Referenced by sla_process_timers().

06074 {
06075    struct sla_station *station;
06076    int res = 0;
06077 
06078    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
06079       struct sla_ringing_trunk *ringing_trunk;
06080       int time_left;
06081 
06082       /* Ignore stations already ringing */
06083       if (sla_check_ringing_station(station))
06084          continue;
06085 
06086       /* Ignore stations already on a call */
06087       if (sla_check_inuse_station(station))
06088          continue;
06089 
06090       /* Ignore stations that don't have one of their trunks ringing */
06091       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
06092          continue;
06093 
06094       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
06095          continue;
06096 
06097       /* If there is no time left, then the station needs to start ringing.
06098        * Return non-zero so that an event will be queued up an event to 
06099        * make that happen. */
06100       if (time_left <= 0) {
06101          res = 1;
06102          continue;
06103       }
06104 
06105       if (time_left < *timeout)
06106          *timeout = time_left;
06107    }
06108 
06109    return res;
06110 }

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

05991 {
05992    struct sla_ringing_trunk *ringing_trunk;
05993    struct sla_ringing_station *ringing_station;
05994    int res = 0;
05995 
05996    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05997       unsigned int ring_timeout = 0;
05998       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
05999       struct sla_trunk_ref *trunk_ref;
06000 
06001       /* If there are any ring timeouts specified for a specific trunk
06002        * on the station, then use the highest per-trunk ring timeout.
06003        * Otherwise, use the ring timeout set for the entire station. */
06004       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
06005          struct sla_station_ref *station_ref;
06006          int trunk_time_elapsed, trunk_time_left;
06007 
06008          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
06009             if (ringing_trunk->trunk == trunk_ref->trunk)
06010                break;
06011          }
06012          if (!ringing_trunk)
06013             continue;
06014 
06015          /* If there is a trunk that is ringing without a timeout, then the
06016           * only timeout that could matter is a global station ring timeout. */
06017          if (!trunk_ref->ring_timeout)
06018             break;
06019 
06020          /* This trunk on this station is ringing and has a timeout.
06021           * However, make sure this trunk isn't still ringing from a
06022           * previous timeout.  If so, don't consider it. */
06023          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
06024             if (station_ref->station == ringing_station->station)
06025                break;
06026          }
06027          if (station_ref)
06028             continue;
06029 
06030          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
06031          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
06032          if (trunk_time_left > final_trunk_time_left)
06033             final_trunk_time_left = trunk_time_left;
06034       }
06035 
06036       /* No timeout was found for ringing trunks, and no timeout for the entire station */
06037       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
06038          continue;
06039 
06040       /* Compute how much time is left for a global station timeout */
06041       if (ringing_station->station->ring_timeout) {
06042          ring_timeout = ringing_station->station->ring_timeout;
06043          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
06044          time_left = (ring_timeout * 1000) - time_elapsed;
06045       }
06046 
06047       /* If the time left based on the per-trunk timeouts is smaller than the
06048        * global station ring timeout, use that. */
06049       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
06050          time_left = final_trunk_time_left;
06051 
06052       /* If there is no time left, the station needs to stop ringing */
06053       if (time_left <= 0) {
06054          AST_LIST_REMOVE_CURRENT(entry);
06055          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
06056          res = 1;
06057          continue;
06058       }
06059 
06060       /* There is still some time left for this station to ring, so save that
06061        * timeout if it is the first event scheduled to occur */
06062       if (time_left < *timeout)
06063          *timeout = time_left;
06064    }
06065    AST_LIST_TRAVERSE_SAFE_END;
06066 
06067    return res;
06068 }

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

05961 {
05962    struct sla_ringing_trunk *ringing_trunk;
05963    int res = 0;
05964 
05965    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05966       int time_left, time_elapsed;
05967       if (!ringing_trunk->trunk->ring_timeout)
05968          continue;
05969       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05970       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
05971       if (time_left <= 0) {
05972          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
05973          AST_LIST_REMOVE_CURRENT(entry);
05974          sla_stop_ringing_trunk(ringing_trunk);
05975          res = 1;
05976          continue;
05977       }
05978       if (time_left < *timeout)
05979          *timeout = time_left;
05980    }
05981    AST_LIST_TRAVERSE_SAFE_END;
05982 
05983    return res;
05984 }

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

References AST_DEVSTATE_CACHABLE, ast_devstate_changed(), AST_LIST_TRAVERSE, and sla_state_to_devstate().

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

05422 {
05423    struct sla_station *station;
05424    struct sla_trunk_ref *trunk_ref;
05425 
05426    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05427       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05428          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
05429             || trunk_ref == exclude)
05430             continue;
05431          trunk_ref->state = state;
05432          ast_devstate_changed(sla_state_to_devstate(state), AST_DEVSTATE_CACHABLE,
05433                     "SLA:%s_%s", station->name, trunk->name);
05434          break;
05435       }
05436    }
05437 }

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

Definition at line 6836 of file app_meetme.c.

References ast_strdupa, and ast_strlen_zero().

Referenced by sla_build_trunk().

06837 {
06838    char *tech, *tech_data;
06839 
06840    tech_data = ast_strdupa(device);
06841    tech = strsep(&tech_data, "/");
06842 
06843    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
06844       return -1;
06845 
06846    return 0;
06847 }

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

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

Referenced by sla_ring_stations().

05710 {
05711    struct sla_failed_station *failed_station;
05712    int res = 0;
05713 
05714    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
05715       if (station != failed_station->station)
05716          continue;
05717       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
05718          AST_LIST_REMOVE_CURRENT(entry);
05719          ast_free(failed_station);
05720          break;
05721       }
05722       res = 1;
05723    }
05724    AST_LIST_TRAVERSE_SAFE_END
05725 
05726    return res;
05727 }

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

Check to see if a station is in use.

Definition at line 5794 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

05795 {
05796    struct sla_trunk_ref *trunk_ref;
05797 
05798    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05799       if (trunk_ref->chan)
05800          return 1;
05801    }
05802 
05803    return 0;
05804 }

static void sla_check_reload ( void   )  [static]

Check if we can do a reload of SLA, and do it if we can.

Definition at line 6152 of file app_meetme.c.

References AST_LIST_EMPTY, ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, sla, and sla_load_config().

Referenced by sla_thread().

06153 {
06154    struct sla_station *station;
06155    struct sla_trunk *trunk;
06156 
06157    ast_mutex_lock(&sla.lock);
06158 
06159    if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
06160       || !AST_LIST_EMPTY(&sla.ringing_stations)) {
06161       ast_mutex_unlock(&sla.lock);
06162       return;
06163    }
06164 
06165    AST_RWLIST_RDLOCK(&sla_stations);
06166    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
06167       if (station->ref_count)
06168          break;
06169    }
06170    AST_RWLIST_UNLOCK(&sla_stations);
06171    if (station) {
06172       ast_mutex_unlock(&sla.lock);
06173       return;
06174    }
06175 
06176    AST_RWLIST_RDLOCK(&sla_trunks);
06177    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
06178       if (trunk->ref_count)
06179          break;
06180    }
06181    AST_RWLIST_UNLOCK(&sla_trunks);
06182    if (trunk) {
06183       ast_mutex_unlock(&sla.lock);
06184       return;
06185    }
06186 
06187    /* yay */
06188    sla_load_config(1);
06189    sla.reload = 0;
06190 
06191    ast_mutex_unlock(&sla.lock);
06192 }

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

05695 {
05696    struct sla_ringing_station *ringing_station;
05697 
05698    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
05699       if (station == ringing_station->station)
05700          return 1;
05701    }
05702 
05703    return 0;
05704 }

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

References ast_tvdiff_ms(), ast_tvnow(), 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().

05826 {
05827    struct sla_trunk_ref *trunk_ref;
05828    unsigned int delay = UINT_MAX;
05829    int time_left, time_elapsed;
05830 
05831    if (!ringing_trunk)
05832       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
05833    else
05834       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
05835 
05836    if (!ringing_trunk || !trunk_ref)
05837       return delay;
05838 
05839    /* If this station has a ring delay specific to the highest priority
05840     * ringing trunk, use that.  Otherwise, use the ring delay specified
05841     * globally for the station. */
05842    delay = trunk_ref->ring_delay;
05843    if (!delay)
05844       delay = station->ring_delay;
05845    if (!delay)
05846       return INT_MAX;
05847 
05848    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05849    time_left = (delay * 1000) - time_elapsed;
05850 
05851    return time_left;
05852 }

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

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

05327 {
05328    struct sla_station_ref *station_ref;
05329    struct sla_trunk_ref *trunk_ref;
05330 
05331    /* For each station that has this call on hold, check for private hold. */
05332    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
05333       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
05334          if (trunk_ref->trunk != trunk || station_ref->station == station)
05335             continue;
05336          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
05337             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
05338             return 1;
05339          return 0;
05340       }
05341    }
05342 
05343    return 0;
05344 }

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

References AST_LIST_TRAVERSE.

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

05558 {
05559    struct sla_station_ref *timed_out_station;
05560 
05561    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
05562       if (station == timed_out_station->station)
05563          return 1;
05564    }
05565 
05566    return 0;
05567 }

static struct sla_trunk_ref* sla_choose_idle_trunk ( const struct sla_station station  )  [static, read]

For a given station, choose the highest priority idle trunk.

Definition at line 6399 of file app_meetme.c.

References AST_LIST_TRAVERSE, and SLA_TRUNK_STATE_IDLE.

Referenced by sla_station_exec().

06400 {
06401    struct sla_trunk_ref *trunk_ref = NULL;
06402 
06403    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06404       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
06405          break;
06406    }
06407 
06408    return trunk_ref;
06409 }

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

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

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

05579 {
05580    struct sla_trunk_ref *s_trunk_ref;
05581    struct sla_ringing_trunk *ringing_trunk = NULL;
05582 
05583    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
05584       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05585          /* Make sure this is the trunk we're looking for */
05586          if (s_trunk_ref->trunk != ringing_trunk->trunk)
05587             continue;
05588 
05589          /* This trunk on the station is ringing.  But, make sure this station
05590           * didn't already time out while this trunk was ringing. */
05591          if (sla_check_timed_out_station(ringing_trunk, station))
05592             continue;
05593 
05594          if (rm)
05595             AST_LIST_REMOVE_CURRENT(entry);
05596 
05597          if (trunk_ref)
05598             *trunk_ref = s_trunk_ref;
05599 
05600          break;
05601       }
05602       AST_LIST_TRAVERSE_SAFE_END;
05603    
05604       if (ringing_trunk)
05605          break;
05606    }
05607 
05608    return ringing_trunk;
05609 }

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

Definition at line 5390 of file app_meetme.c.

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

Referenced by sla_ring_station().

05391 {
05392    struct sla_ringing_station *ringing_station;
05393 
05394    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
05395       return NULL;
05396 
05397    ringing_station->station = station;
05398    ringing_station->ring_begin = ast_tvnow();
05399 
05400    return ringing_station;
05401 }

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

Definition at line 5378 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().

05379 {
05380    struct sla_station_ref *station_ref;
05381 
05382    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
05383       return NULL;
05384 
05385    station_ref->station = station;
05386 
05387    return station_ref;
05388 }

static void sla_destroy ( void   )  [static]

Definition at line 6806 of file app_meetme.c.

References ast_cond_destroy, ast_cond_signal, ast_context_destroy(), ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, AST_RWLIST_REMOVE_HEAD, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, destroy_station(), destroy_trunk(), sla, and sla_registrar.

Referenced by unload_module().

06807 {
06808    struct sla_trunk *trunk;
06809    struct sla_station *station;
06810 
06811    AST_RWLIST_WRLOCK(&sla_trunks);
06812    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
06813       destroy_trunk(trunk);
06814    AST_RWLIST_UNLOCK(&sla_trunks);
06815 
06816    AST_RWLIST_WRLOCK(&sla_stations);
06817    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
06818       destroy_station(station);
06819    AST_RWLIST_UNLOCK(&sla_stations);
06820 
06821    if (sla.thread != AST_PTHREADT_NULL) {
06822       ast_mutex_lock(&sla.lock);
06823       sla.stop = 1;
06824       ast_cond_signal(&sla.cond);
06825       ast_mutex_unlock(&sla.lock);
06826       pthread_join(sla.thread, NULL);
06827    }
06828 
06829    /* Drop any created contexts from the dialplan */
06830    ast_context_destroy(NULL, sla_registrar);
06831 
06832    ast_mutex_destroy(&sla.lock);
06833    ast_cond_destroy(&sla.cond);
06834 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 5548 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

05549 {
05550    sla_queue_event(SLA_EVENT_DIAL_STATE);
05551 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 5313 of file app_meetme.c.

References AST_RWLIST_TRAVERSE.

Referenced by sla_station_exec().

05314 {
05315    struct sla_station *station = NULL;
05316 
05317    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
05318       if (!strcasecmp(station->name, name))
05319          break;
05320    }
05321 
05322    return station;
05323 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 5298 of file app_meetme.c.

References AST_RWLIST_TRAVERSE.

Referenced by sla_trunk_exec().

05299 {
05300    struct sla_trunk *trunk = NULL;
05301 
05302    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05303       if (!strcasecmp(trunk->name, name))
05304          break;
05305    }
05306 
05307    return trunk;
05308 }

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

Definition at line 5806 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_check_station_delay().

05808 {
05809    struct sla_trunk_ref *trunk_ref = NULL;
05810 
05811    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05812       if (trunk_ref->trunk == trunk)
05813          break;
05814    }
05815 
05816    return trunk_ref;
05817 }

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

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

05355 {
05356    struct sla_trunk_ref *trunk_ref = NULL;
05357 
05358    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05359       if (strcasecmp(trunk_ref->trunk->name, name))
05360          continue;
05361 
05362       if ( (trunk_ref->trunk->barge_disabled 
05363          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
05364          (trunk_ref->trunk->hold_stations 
05365          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
05366          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
05367          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
05368       {
05369          trunk_ref = NULL;
05370       }
05371 
05372       break;
05373    }
05374 
05375    return trunk_ref;
05376 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 5611 of file app_meetme.c.

References ALL_TRUNK_REFS, answer_trunk_chan(), ast_cond_destroy, ast_cond_init, ast_cond_wait, ast_debug, ast_dial_answered(), ast_dial_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_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_destroy, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_detached_background, run_station_args::cond, run_station_args::cond_lock, run_station(), sla, sla_change_trunk_state(), sla_choose_ringing_trunk(), SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_queue_event(), SLA_STATION_HANGUP_NORMAL, sla_stop_ringing_station(), SLA_TRUNK_STATE_UP, run_station_args::station, sla_ringing_station::station, sla_ringing_trunk::trunk, and run_station_args::trunk_ref.

Referenced by sla_thread().

05612 {
05613    struct sla_ringing_station *ringing_station;
05614 
05615    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05616       struct sla_trunk_ref *s_trunk_ref = NULL;
05617       struct sla_ringing_trunk *ringing_trunk = NULL;
05618       struct run_station_args args;
05619       enum ast_dial_result dial_res;
05620       pthread_t dont_care;
05621       ast_mutex_t cond_lock;
05622       ast_cond_t cond;
05623 
05624       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
05625       case AST_DIAL_RESULT_HANGUP:
05626       case AST_DIAL_RESULT_INVALID:
05627       case AST_DIAL_RESULT_FAILED:
05628       case AST_DIAL_RESULT_TIMEOUT:
05629       case AST_DIAL_RESULT_UNANSWERED:
05630          AST_LIST_REMOVE_CURRENT(entry);
05631          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
05632          break;
05633       case AST_DIAL_RESULT_ANSWERED:
05634          AST_LIST_REMOVE_CURRENT(entry);
05635          /* Find the appropriate trunk to answer. */
05636          ast_mutex_lock(&sla.lock);
05637          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
05638          ast_mutex_unlock(&sla.lock);
05639          if (!ringing_trunk) {
05640             /* This case happens in a bit of a race condition.  If two stations answer
05641              * the outbound call at the same time, the first one will get connected to
05642              * the trunk.  When the second one gets here, it will not see any trunks
05643              * ringing so we have no idea what to conect it to.  So, we just hang up
05644              * on it. */
05645             ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
05646             ast_dial_join(ringing_station->station->dial);
05647             ast_dial_destroy(ringing_station->station->dial);
05648             ringing_station->station->dial = NULL;
05649             ast_free(ringing_station);
05650             break;
05651          }
05652          /* Track the channel that answered this trunk */
05653          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
05654          /* Actually answer the trunk */
05655          answer_trunk_chan(ringing_trunk->trunk->chan);
05656          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05657          /* Now, start a thread that will connect this station to the trunk.  The rest of
05658           * the code here sets up the thread and ensures that it is able to save the arguments
05659           * before they are no longer valid since they are allocated on the stack. */
05660          args.trunk_ref = s_trunk_ref;
05661          args.station = ringing_station->station;
05662          args.cond = &cond;
05663          args.cond_lock = &cond_lock;
05664          ast_free(ringing_trunk);
05665          ast_free(ringing_station);
05666          ast_mutex_init(&cond_lock);
05667          ast_cond_init(&cond, NULL);
05668          ast_mutex_lock(&cond_lock);
05669          ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
05670          ast_cond_wait(&cond, &cond_lock);
05671          ast_mutex_unlock(&cond_lock);
05672          ast_mutex_destroy(&cond_lock);
05673          ast_cond_destroy(&cond);
05674          break;
05675       case AST_DIAL_RESULT_TRYING:
05676       case AST_DIAL_RESULT_RINGING:
05677       case AST_DIAL_RESULT_PROGRESS:
05678       case AST_DIAL_RESULT_PROCEEDING:
05679          break;
05680       }
05681       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
05682          /* Queue up reprocessing ringing trunks, and then ringing stations again */
05683          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05684          sla_queue_event(SLA_EVENT_DIAL_STATE);
05685          break;
05686       }
05687    }
05688    AST_LIST_TRAVERSE_SAFE_END;
05689 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

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

05937 {
05938    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
05939    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
05940    ast_devstate_changed(AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, "SLA:%s_%s",
05941               event->station->name, event->trunk_ref->trunk->name);
05942    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
05943       INACTIVE_TRUNK_REFS, event->trunk_ref);
05944 
05945    if (event->trunk_ref->trunk->active_stations == 1) {
05946       /* The station putting it on hold is the only one on the call, so start
05947        * Music on hold to the trunk. */
05948       event->trunk_ref->trunk->on_hold = 1;
05949       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
05950    }
05951 
05952    ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
05953    event->trunk_ref->chan = NULL;
05954 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 5926 of file app_meetme.c.

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

Referenced by sla_thread().

05927 {
05928    ast_mutex_lock(&sla.lock);
05929    sla_ring_stations();
05930    ast_mutex_unlock(&sla.lock);
05931 
05932    /* Find stations that shouldn't be ringing anymore. */
05933    sla_hangup_stations();
05934 }

static void sla_hangup_stations ( void   )  [static]

Definition at line 5898 of file app_meetme.c.

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

Referenced by sla_handle_ringing_trunk_event().

05899 {
05900    struct sla_trunk_ref *trunk_ref;
05901    struct sla_ringing_station *ringing_station;
05902 
05903    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05904       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05905          struct sla_ringing_trunk *ringing_trunk;
05906          ast_mutex_lock(&sla.lock);
05907          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05908             if (trunk_ref->trunk == ringing_trunk->trunk)
05909                break;
05910          }
05911          ast_mutex_unlock(&sla.lock);
05912          if (ringing_trunk)
05913             break;
05914       }
05915       if (!trunk_ref) {
05916          AST_LIST_REMOVE_CURRENT(entry);
05917          ast_dial_join(ringing_station->station->dial);
05918          ast_dial_destroy(ringing_station->station->dial);
05919          ringing_station->station->dial = NULL;
05920          ast_free(ringing_station);
05921       }
05922    }
05923    AST_LIST_TRAVERSE_SAFE_END
05924 }

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

Definition at line 1703 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01704 {
01705    const char *hold = "Unknown";
01706 
01707    switch (hold_access) {
01708    case SLA_HOLD_OPEN:
01709       hold = "Open";
01710       break;
01711    case SLA_HOLD_PRIVATE:
01712       hold = "Private";
01713    default:
01714       break;
01715    }
01716 
01717    return hold;
01718 }

static int sla_load_config ( int  reload  )  [static]

Definition at line 7086 of file app_meetme.c.

References ast_category_browse(), ast_cond_init, ast_config_destroy(), ast_config_load, ast_free, AST_LIST_EMPTY, ast_log(), ast_mutex_init, ast_pthread_create, AST_PTHREADT_NULL, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, ast_true(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, LOG_ERROR, LOG_WARNING, sla, sla_build_station(), sla_build_trunk(), SLA_CONFIG_FILE, sla_thread(), and type.

Referenced by load_config(), and sla_check_reload().

07087 {
07088    struct ast_config *cfg;
07089    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
07090    const char *cat = NULL;
07091    int res = 0;
07092    const char *val;
07093 
07094    if (!reload) {
07095       ast_mutex_init(&sla.lock);
07096       ast_cond_init(&sla.cond, NULL);
07097    }
07098 
07099    if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
07100       return 0; /* Treat no config as normal */
07101    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
07102       return 0;
07103    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
07104       ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format.  Aborting.\n");
07105       return 0;
07106    }
07107 
07108    if (reload) {
07109       struct sla_station *station;
07110       struct sla_trunk *trunk;
07111 
07112       /* We need to actually delete the previous versions of trunks and stations now */
07113       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_stations, station, entry) {
07114          AST_RWLIST_REMOVE_CURRENT(entry);
07115          ast_free(station);
07116       }
07117       AST_RWLIST_TRAVERSE_SAFE_END;
07118 
07119       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_trunks, trunk, entry) {
07120          AST_RWLIST_REMOVE_CURRENT(entry);
07121          ast_free(trunk);
07122       }
07123       AST_RWLIST_TRAVERSE_SAFE_END;
07124    }
07125 
07126    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
07127       sla.attempt_callerid = ast_true(val);
07128 
07129    while ((cat = ast_category_browse(cfg, cat)) && !res) {
07130       const char *type;
07131       if (!strcasecmp(cat, "general"))
07132          continue;
07133       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
07134          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
07135             SLA_CONFIG_FILE);
07136          continue;
07137       }
07138       if (!strcasecmp(type, "trunk"))
07139          res = sla_build_trunk(cfg, cat);
07140       else if (!strcasecmp(type, "station"))
07141          res = sla_build_station(cfg, cat);
07142       else {
07143          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
07144             SLA_CONFIG_FILE, type);
07145       }
07146    }
07147 
07148    ast_config_destroy(cfg);
07149 
07150    /* Even if we don't have any stations, we may after a reload and we need to
07151     * be able to process the SLA_EVENT_RELOAD event in that case */
07152    if (sla.thread == AST_PTHREADT_NULL && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_trunks))) {
07153       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
07154    }
07155 
07156    return res;
07157 }

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

06115 {
06116    unsigned int timeout = UINT_MAX;
06117    struct timeval wait;
06118    unsigned int change_made = 0;
06119 
06120    /* Check for ring timeouts on ringing trunks */
06121    if (sla_calc_trunk_timeouts(&timeout))
06122       change_made = 1;
06123 
06124    /* Check for ring timeouts on ringing stations */
06125    if (sla_calc_station_timeouts(&timeout))
06126       change_made = 1;
06127 
06128    /* Check for station ring delays */
06129    if (sla_calc_station_delays(&timeout))
06130       change_made = 1;
06131 
06132    /* queue reprocessing of ringing trunks */
06133    if (change_made)
06134       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
06135 
06136    /* No timeout */
06137    if (timeout == UINT_MAX)
06138       return 0;
06139 
06140    if (ts) {
06141       wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
06142       ts->tv_sec = wait.tv_sec;
06143       ts->tv_nsec = wait.tv_usec * 1000;
06144    }
06145 
06146    return 1;
06147 }

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

References ast_debug, AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdupa, ast_strlen_zero(), ast_conference::confno, LOG_ERROR, and sla_queue_event_full().

Referenced by conf_run().

02028 {
02029    struct sla_station *station;
02030    struct sla_trunk_ref *trunk_ref = NULL;
02031    char *trunk_name;
02032 
02033    trunk_name = ast_strdupa(conf->confno);
02034    strsep(&trunk_name, "_");
02035    if (ast_strlen_zero(trunk_name)) {
02036       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
02037       return;
02038    }
02039 
02040    AST_RWLIST_RDLOCK(&sla_stations);
02041    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
02042       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
02043          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
02044             break;
02045       }
02046       if (trunk_ref)
02047          break;
02048    }
02049    AST_RWLIST_UNLOCK(&sla_stations);
02050 
02051    if (!trunk_ref) {
02052       ast_debug(1, "Trunk not found for event!\n");
02053       return;
02054    }
02055 
02056    sla_queue_event_full(type, trunk_ref, station, 1);
02057 }

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

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

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

01990 {
01991    struct sla_event *event;
01992 
01993    if (sla.thread == AST_PTHREADT_NULL) {
01994       return;
01995    }
01996 
01997    if (!(event = ast_calloc(1, sizeof(*event))))
01998       return;
01999 
02000    event->type = type;
02001    event->trunk_ref = trunk_ref;
02002    event->station = station;
02003 
02004    if (!lock) {
02005       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
02006       return;
02007    }
02008 
02009    ast_mutex_lock(&sla.lock);
02010    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
02011    ast_cond_signal(&sla.cond);
02012    ast_mutex_unlock(&sla.lock);
02013 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 2015 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

02016 {
02017    sla_queue_event_full(type, NULL, NULL, 0);
02018 }

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

References ast_calloc, ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_TRYING, ast_dial_run(), ast_dial_set_state_callback(), AST_LIST_INSERT_HEAD, ast_party_caller_free(), ast_party_caller_init(), ast_strdupa, ast_tvnow(), sla_failed_station::last_try, sla, sla_create_ringing_station(), sla_dial_state_callback(), sla_failed_station::station, and sla_ringing_trunk::trunk.

Referenced by sla_ring_stations().

05733 {
05734    char *tech, *tech_data;
05735    struct ast_dial *dial;
05736    struct sla_ringing_station *ringing_station;
05737    enum ast_dial_result res;
05738    int caller_is_saved;
05739    struct ast_party_caller caller;
05740 
05741    if (!(dial = ast_dial_create()))
05742       return -1;
05743 
05744    ast_dial_set_state_callback(dial, sla_dial_state_callback);
05745    tech_data = ast_strdupa(station->device);
05746    tech = strsep(&tech_data, "/");
05747 
05748    if (ast_dial_append(dial, tech, tech_data) == -1) {
05749       ast_dial_destroy(dial);
05750       return -1;
05751    }
05752 
05753    /* Do we need to save off the caller ID data? */
05754    caller_is_saved = 0;
05755    if (!sla.attempt_callerid) {
05756       caller_is_saved = 1;
05757       caller = ringing_trunk->trunk->chan->caller;
05758       ast_party_caller_init(&ringing_trunk->trunk->chan->caller);
05759    }
05760 
05761    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
05762    
05763    /* Restore saved caller ID */
05764    if (caller_is_saved) {
05765       ast_party_caller_free(&ringing_trunk->trunk->chan->caller);
05766       ringing_trunk->trunk->chan->caller = caller;
05767    }
05768    
05769    if (res != AST_DIAL_RESULT_TRYING) {
05770       struct sla_failed_station *failed_station;
05771       ast_dial_destroy(dial);
05772       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
05773          return -1;
05774       failed_station->station = station;
05775       failed_station->last_try = ast_tvnow();
05776       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
05777       return -1;
05778    }
05779    if (!(ringing_station = sla_create_ringing_station(station))) {
05780       ast_dial_join(dial);
05781       ast_dial_destroy(dial);
05782       return -1;
05783    }
05784 
05785    station->dial = dial;
05786 
05787    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
05788 
05789    return 0;
05790 }

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

05858 {
05859    struct sla_station_ref *station_ref;
05860    struct sla_ringing_trunk *ringing_trunk;
05861 
05862    /* Make sure that every station that uses at least one of the ringing
05863     * trunks, is ringing. */
05864    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05865       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
05866          int time_left;
05867 
05868          /* Is this station already ringing? */
05869          if (sla_check_ringing_station(station_ref->station))
05870             continue;
05871 
05872          /* Is this station already in a call? */
05873          if (sla_check_inuse_station(station_ref->station))
05874             continue;
05875 
05876          /* Did we fail to dial this station earlier?  If so, has it been
05877           * a minute since we tried? */
05878          if (sla_check_failed_station(station_ref->station))
05879             continue;
05880 
05881          /* If this station already timed out while this trunk was ringing,
05882           * do not dial it again for this ringing trunk. */
05883          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
05884             continue;
05885 
05886          /* Check for a ring delay in progress */
05887          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
05888          if (time_left != INT_MAX && time_left > 0)
05889             continue;
05890 
05891          /* It is time to make this station begin to ring.  Do it! */
05892          sla_ring_station(ringing_trunk, station_ref->station);
05893       }
05894    }
05895    /* Now, all of the stations that should be ringing, are ringing. */
05896 }

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

Definition at line 1785 of file app_meetme.c.

References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, S_OR, sla_hold_str(), trunkstate2str(), and ast_cli_entry::usage.

01786 {
01787    const struct sla_station *station;
01788 
01789    switch (cmd) {
01790    case CLI_INIT:
01791       e->command = "sla show stations";
01792       e->usage =
01793          "Usage: sla show stations\n"
01794          "       This will list all stations defined in sla.conf\n";
01795       return NULL;
01796    case CLI_GENERATE:
01797       return NULL;
01798    }
01799 
01800    ast_cli(a->fd, "\n" 
01801                "=============================================================\n"
01802                "=== Configured SLA Stations =================================\n"
01803                "=============================================================\n"
01804                "===\n");
01805    AST_RWLIST_RDLOCK(&sla_stations);
01806    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01807       struct sla_trunk_ref *trunk_ref;
01808       char ring_timeout[16] = "(none)";
01809       char ring_delay[16] = "(none)";
01810       if (station->ring_timeout) {
01811          snprintf(ring_timeout, sizeof(ring_timeout), 
01812             "%u", station->ring_timeout);
01813       }
01814       if (station->ring_delay) {
01815          snprintf(ring_delay, sizeof(ring_delay), 
01816             "%u", station->ring_delay);
01817       }
01818       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01819                   "=== Station Name:    %s\n"
01820                   "=== ==> Device:      %s\n"
01821                   "=== ==> AutoContext: %s\n"
01822                   "=== ==> RingTimeout: %s\n"
01823                   "=== ==> RingDelay:   %s\n"
01824                   "=== ==> HoldAccess:  %s\n"
01825                   "=== ==> Trunks ...\n",
01826                   station->name, station->device,
01827                   S_OR(station->autocontext, "(none)"), 
01828                   ring_timeout, ring_delay,
01829                   sla_hold_str(station->hold_access));
01830       AST_RWLIST_RDLOCK(&sla_trunks);
01831       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01832          if (trunk_ref->ring_timeout) {
01833             snprintf(ring_timeout, sizeof(ring_timeout),
01834                "%u", trunk_ref->ring_timeout);
01835          } else
01836             strcpy(ring_timeout, "(none)");
01837          if (trunk_ref->ring_delay) {
01838             snprintf(ring_delay, sizeof(ring_delay),
01839                "%u", trunk_ref->ring_delay);
01840          } else
01841             strcpy(ring_delay, "(none)");
01842             ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
01843                      "===       ==> State:       %s\n"
01844                      "===       ==> RingTimeout: %s\n"
01845                      "===       ==> RingDelay:   %s\n",
01846                      trunk_ref->trunk->name,
01847                      trunkstate2str(trunk_ref->state),
01848                      ring_timeout, ring_delay);
01849       }
01850       AST_RWLIST_UNLOCK(&sla_trunks);
01851       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01852                   "===\n");
01853    }
01854    AST_RWLIST_UNLOCK(&sla_stations);
01855    ast_cli(a->fd, "============================================================\n"
01856                "\n");
01857 
01858    return CLI_SUCCESS;
01859 }

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

Definition at line 1720 of file app_meetme.c.

References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, S_OR, sla_hold_str(), and ast_cli_entry::usage.

01721 {
01722    const struct sla_trunk *trunk;
01723 
01724    switch (cmd) {
01725    case CLI_INIT:
01726       e->command = "sla show trunks";
01727       e->usage =
01728          "Usage: sla show trunks\n"
01729          "       This will list all trunks defined in sla.conf\n";
01730       return NULL;
01731    case CLI_GENERATE:
01732       return NULL;
01733    }
01734 
01735    ast_cli(a->fd, "\n"
01736                "=============================================================\n"
01737                "=== Configured SLA Trunks ===================================\n"
01738                "=============================================================\n"
01739                "===\n");
01740    AST_RWLIST_RDLOCK(&sla_trunks);
01741    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01742       struct sla_station_ref *station_ref;
01743       char ring_timeout[16] = "(none)";
01744       if (trunk->ring_timeout)
01745          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01746       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01747                   "=== Trunk Name:       %s\n"
01748                   "=== ==> Device:       %s\n"
01749                   "=== ==> AutoContext:  %s\n"
01750                   "=== ==> RingTimeout:  %s\n"
01751                   "=== ==> BargeAllowed: %s\n"
01752                   "=== ==> HoldAccess:   %s\n"
01753                   "=== ==> Stations ...\n",
01754                   trunk->name, trunk->device, 
01755                   S_OR(trunk->autocontext, "(none)"), 
01756                   ring_timeout,
01757                   trunk->barge_disabled ? "No" : "Yes",
01758                   sla_hold_str(trunk->hold_access));
01759       AST_RWLIST_RDLOCK(&sla_stations);
01760       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01761          ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
01762       AST_RWLIST_UNLOCK(&sla_stations);
01763       ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
01764    }
01765    AST_RWLIST_UNLOCK(&sla_trunks);
01766    ast_cli(a->fd, "=============================================================\n\n");
01767 
01768    return CLI_SUCCESS;
01769 }

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

Definition at line 6730 of file app_meetme.c.

References AST_DEVICE_INVALID, AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_strdupa, LOG_ERROR, and sla_state_to_devstate().

Referenced by load_module().

06731 {
06732    char *buf, *station_name, *trunk_name;
06733    struct sla_station *station;
06734    struct sla_trunk_ref *trunk_ref;
06735    enum ast_device_state res = AST_DEVICE_INVALID;
06736 
06737    trunk_name = buf = ast_strdupa(data);
06738    station_name = strsep(&trunk_name, "_");
06739 
06740    AST_RWLIST_RDLOCK(&sla_stations);
06741    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
06742       if (strcasecmp(station_name, station->name))
06743          continue;
06744       AST_RWLIST_RDLOCK(&sla_trunks);
06745       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06746          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
06747             break;
06748       }
06749       if (!trunk_ref) {
06750          AST_RWLIST_UNLOCK(&sla_trunks);
06751          break;
06752       }
06753       res = sla_state_to_devstate(trunk_ref->state);
06754       AST_RWLIST_UNLOCK(&sla_trunks);
06755    }
06756    AST_RWLIST_UNLOCK(&sla_stations);
06757 
06758    if (res == AST_DEVICE_INVALID) {
06759       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
06760          trunk_name, station_name);
06761    }
06762 
06763    return res;
06764 }

static enum ast_device_state sla_state_to_devstate ( enum sla_trunk_state  state  )  [static]
static int sla_station_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 6411 of file app_meetme.c.

References admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), ast_answer(), ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_cond_destroy, ast_cond_init, ast_cond_wait, AST_CONTROL_UNHOLD, ast_debug, AST_DEVICE_INUSE, AST_DEVSTATE_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_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, 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(), free, LOG_NOTICE, LOG_WARNING, MAX_CONFNUM, pbx_builtin_setvar_helper(), sla, sla_change_trunk_state(), sla_choose_idle_trunk(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_find_station(), sla_find_trunk_ref_byname(), sla_queue_event(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, sla_ringing_trunk::trunk, and dial_trunk_args::trunk_ref.

Referenced by load_module().

06412 {
06413    char *station_name, *trunk_name;
06414    struct sla_station *station;
06415    struct sla_trunk_ref *trunk_ref = NULL;
06416    char conf_name[MAX_CONFNUM];
06417    struct ast_flags64 conf_flags = { 0 };
06418    struct ast_conference *conf;
06419 
06420    if (ast_strlen_zero(data)) {
06421       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
06422       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06423       return 0;
06424    }
06425 
06426    trunk_name = ast_strdupa(data);
06427    station_name = strsep(&trunk_name, "_");
06428 
06429    if (ast_strlen_zero(station_name)) {
06430       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
06431       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06432       return 0;
06433    }
06434 
06435    AST_RWLIST_RDLOCK(&sla_stations);
06436    station = sla_find_station(station_name);
06437    if (station)
06438       ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
06439    AST_RWLIST_UNLOCK(&sla_stations);
06440 
06441    if (!station) {
06442       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
06443       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06444       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06445       return 0;
06446    }
06447 
06448    AST_RWLIST_RDLOCK(&sla_trunks);
06449    if (!ast_strlen_zero(trunk_name)) {
06450       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
06451    } else
06452       trunk_ref = sla_choose_idle_trunk(station);
06453    AST_RWLIST_UNLOCK(&sla_trunks);
06454 
06455    if (!trunk_ref) {
06456       if (ast_strlen_zero(trunk_name))
06457          ast_log(LOG_NOTICE, "No trunks available for call.\n");
06458       else {
06459          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
06460             "'%s' due to access controls.\n", trunk_name);
06461       }
06462       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
06463       ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06464       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06465       return 0;
06466    }
06467 
06468    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
06469       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
06470          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06471       else {
06472          trunk_ref->state = SLA_TRUNK_STATE_UP;
06473          ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE,
06474                     "SLA:%s_%s", station->name, trunk_ref->trunk->name);
06475       }
06476    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
06477       struct sla_ringing_trunk *ringing_trunk;
06478 
06479       ast_mutex_lock(&sla.lock);
06480       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
06481          if (ringing_trunk->trunk == trunk_ref->trunk) {
06482             AST_LIST_REMOVE_CURRENT(entry);
06483             break;
06484          }
06485       }
06486       AST_LIST_TRAVERSE_SAFE_END
06487       ast_mutex_unlock(&sla.lock);
06488 
06489       if (ringing_trunk) {
06490          answer_trunk_chan(ringing_trunk->trunk->chan);
06491          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06492 
06493          free(ringing_trunk);
06494 
06495          /* Queue up reprocessing ringing trunks, and then ringing stations again */
06496          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06497          sla_queue_event(SLA_EVENT_DIAL_STATE);
06498       }
06499    }
06500 
06501    trunk_ref->chan = chan;
06502 
06503    if (!trunk_ref->trunk->chan) {
06504       ast_mutex_t cond_lock;
06505       ast_cond_t cond;
06506       pthread_t dont_care;
06507       struct dial_trunk_args args = {
06508          .trunk_ref = trunk_ref,
06509          .station = station,
06510          .cond_lock = &cond_lock,
06511          .cond = &cond,
06512       };
06513       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06514       /* Create a thread to dial the trunk and dump it into the conference.
06515        * However, we want to wait until the trunk has been dialed and the
06516        * conference is created before continuing on here. */
06517       ast_autoservice_start(chan);
06518       ast_mutex_init(&cond_lock);
06519       ast_cond_init(&cond, NULL);
06520       ast_mutex_lock(&cond_lock);
06521       ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
06522       ast_cond_wait(&cond, &cond_lock);
06523       ast_mutex_unlock(&cond_lock);
06524       ast_mutex_destroy(&cond_lock);
06525       ast_cond_destroy(&cond);
06526       ast_autoservice_stop(chan);
06527       if (!trunk_ref->trunk->chan) {
06528          ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
06529          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
06530          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06531          trunk_ref->chan = NULL;
06532          ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06533          sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06534          return 0;
06535       }
06536    }
06537 
06538    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
06539       trunk_ref->trunk->on_hold) {
06540       trunk_ref->trunk->on_hold = 0;
06541       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
06542       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06543    }
06544 
06545    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
06546    ast_set_flag64(&conf_flags, 
06547       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
06548    ast_answer(chan);
06549    conf = build_conf(conf_name, "", "", 0, 0, 1, chan, NULL);
06550    if (conf) {
06551       conf_run(chan, conf, &conf_flags, NULL);
06552       dispose_conf(conf);
06553       conf = NULL;
06554    }
06555    trunk_ref->chan = NULL;
06556    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
06557       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
06558       strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
06559       admin_exec(NULL, conf_name);
06560       trunk_ref->trunk->hold_stations = 0;
06561       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06562    }
06563    
06564    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
06565 
06566    ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06567    sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06568 
06569    return 0;
06570 }

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

Definition at line 5513 of file app_meetme.c.

References ast_dial_destroy(), ast_dial_join(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, sla, sla_create_station_ref(), 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().

05515 {
05516    struct sla_ringing_trunk *ringing_trunk;
05517    struct sla_trunk_ref *trunk_ref;
05518    struct sla_station_ref *station_ref;
05519 
05520    ast_dial_join(ringing_station->station->dial);
05521    ast_dial_destroy(ringing_station->station->dial);
05522    ringing_station->station->dial = NULL;
05523 
05524    if (hangup == SLA_STATION_HANGUP_NORMAL)
05525       goto done;
05526 
05527    /* If the station is being hung up because of a timeout, then add it to the
05528     * list of timed out stations on each of the ringing trunks.  This is so
05529     * that when doing further processing to figure out which stations should be
05530     * ringing, which trunk to answer, determining timeouts, etc., we know which
05531     * ringing trunks we should ignore. */
05532    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05533       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05534          if (ringing_trunk->trunk == trunk_ref->trunk)
05535             break;
05536       }
05537       if (!trunk_ref)
05538          continue;
05539       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
05540          continue;
05541       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
05542    }
05543 
05544 done:
05545    ast_free(ringing_station);
05546 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 5498 of file app_meetme.c.

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

Referenced by sla_calc_trunk_timeouts().

05499 {
05500    char buf[80];
05501    struct sla_station_ref *station_ref;
05502 
05503    snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
05504    admin_exec(NULL, buf);
05505    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05506 
05507    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
05508       ast_free(station_ref);
05509 
05510    ast_free(ringing_trunk);
05511 }

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

Definition at line 6194 of file app_meetme.c.

References ast_cond_timedwait, ast_cond_wait, ast_free, AST_LIST_EMPTY, AST_LIST_REMOVE_HEAD, ast_mutex_lock, ast_mutex_unlock, sla, sla_check_reload(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_DIAL_STATE, SLA_EVENT_HOLD, SLA_EVENT_RELOAD, SLA_EVENT_RINGING_TRUNK, sla_handle_dial_state_event(), sla_handle_hold_event(), sla_handle_ringing_trunk_event(), sla_process_timers(), and sla_event::type.

Referenced by sla_load_config().

06195 {
06196    struct sla_failed_station *failed_station;
06197    struct sla_ringing_station *ringing_station;
06198 
06199    ast_mutex_lock(&sla.lock);
06200 
06201    while (!sla.stop) {
06202       struct sla_event *event;
06203       struct timespec ts = { 0, };
06204       unsigned int have_timeout = 0;
06205 
06206       if (AST_LIST_EMPTY(&sla.event_q)) {
06207          if ((have_timeout = sla_process_timers(&ts)))
06208             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
06209          else
06210             ast_cond_wait(&sla.cond, &sla.lock);
06211          if (sla.stop)
06212             break;
06213       }
06214 
06215       if (have_timeout)
06216          sla_process_timers(NULL);
06217 
06218       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
06219          ast_mutex_unlock(&sla.lock);
06220          switch (event->type) {
06221          case SLA_EVENT_HOLD:
06222             sla_handle_hold_event(event);
06223             break;
06224          case SLA_EVENT_DIAL_STATE:
06225             sla_handle_dial_state_event();
06226             break;
06227          case SLA_EVENT_RINGING_TRUNK:
06228             sla_handle_ringing_trunk_event();
06229             break;
06230          case SLA_EVENT_RELOAD:
06231             sla.reload = 1;
06232          case SLA_EVENT_CHECK_RELOAD:
06233             break;
06234          }
06235          ast_free(event);
06236          ast_mutex_lock(&sla.lock);
06237       }
06238 
06239       if (sla.reload) {
06240          sla_check_reload();
06241       }
06242    }
06243 
06244    ast_mutex_unlock(&sla.lock);
06245 
06246    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
06247       ast_free(ringing_station);
06248 
06249    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
06250       ast_free(failed_station);
06251 
06252    return NULL;
06253 }

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

Definition at line 6618 of file app_meetme.c.

References ALL_TRUNK_REFS, args, AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_free, ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_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(), sla, sla_change_trunk_state(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), SLA_TRUNK_OPT_ARG_ARRAY_SIZE, SLA_TRUNK_OPT_MOH, SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by load_module().

06619 {
06620    char conf_name[MAX_CONFNUM];
06621    struct ast_conference *conf;
06622    struct ast_flags64 conf_flags = { 0 };
06623    struct sla_trunk *trunk;
06624    struct sla_ringing_trunk *ringing_trunk;
06625    AST_DECLARE_APP_ARGS(args,
06626       AST_APP_ARG(trunk_name);
06627       AST_APP_ARG(options);
06628    );
06629    char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
06630    struct ast_flags opt_flags = { 0 };
06631    char *parse;
06632 
06633    if (ast_strlen_zero(data)) {
06634       ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
06635       return -1;
06636    }
06637 
06638    parse = ast_strdupa(data);
06639    AST_STANDARD_APP_ARGS(args, parse);
06640    if (args.argc == 2) {
06641       if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
06642          ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
06643          return -1;
06644       }
06645    }
06646 
06647    AST_RWLIST_RDLOCK(&sla_trunks);
06648    trunk = sla_find_trunk(args.trunk_name);
06649    if (trunk)
06650       ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
06651    AST_RWLIST_UNLOCK(&sla_trunks);
06652 
06653    if (!trunk) {
06654       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
06655       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06656       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06657       return 0;
06658    }
06659 
06660    if (trunk->chan) {
06661       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
06662          args.trunk_name);
06663       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06664       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06665       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06666       return 0;
06667    }
06668 
06669    trunk->chan = chan;
06670 
06671    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
06672       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06673       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06674       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06675       return 0;
06676    }
06677 
06678    snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
06679    conf = build_conf(conf_name, "", "", 1, 1, 1, chan, NULL);
06680    if (!conf) {
06681       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06682       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06683       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06684       return 0;
06685    }
06686    ast_set_flag64(&conf_flags, 
06687       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
06688 
06689    if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
06690       ast_indicate(chan, -1);
06691       ast_set_flag64(&conf_flags, CONFFLAG_MOH);
06692    } else
06693       ast_indicate(chan, AST_CONTROL_RINGING);
06694 
06695    conf_run(chan, conf, &conf_flags, opts);
06696    dispose_conf(conf);
06697    conf = NULL;
06698    trunk->chan = NULL;
06699    trunk->on_hold = 0;
06700 
06701    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06702 
06703    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
06704       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
06705 
06706    /* Remove the entry from the list of ringing trunks if it is still there. */
06707    ast_mutex_lock(&sla.lock);
06708    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
06709       if (ringing_trunk->trunk == trunk) {
06710          AST_LIST_REMOVE_CURRENT(entry);
06711          break;
06712       }
06713    }
06714    AST_LIST_TRAVERSE_SAFE_END;
06715    ast_mutex_unlock(&sla.lock);
06716    if (ringing_trunk) {
06717       ast_free(ringing_trunk);
06718       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
06719       /* Queue reprocessing of ringing trunks to make stations stop ringing
06720        * that shouldn't be ringing after this trunk stopped. */
06721       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06722    }
06723 
06724    ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06725    sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06726 
06727    return 0;
06728 }

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

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

01772 {
01773 #define S(e) case e: return # e;
01774    switch (state) {
01775    S(SLA_TRUNK_STATE_IDLE)
01776    S(SLA_TRUNK_STATE_RINGING)
01777    S(SLA_TRUNK_STATE_UP)
01778    S(SLA_TRUNK_STATE_ONHOLD)
01779    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01780    }
01781    return "Uknown State";
01782 #undef S
01783 }

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

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

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

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

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

01092 {
01093    tweak_volume(&user->talk, action);
01094    /* attempt to make the adjustment in the channel driver;
01095       if successful, don't adjust in the frame reading routine
01096    */
01097    if (!set_talk_volume(user, user->talk.desired))
01098       user->talk.actual = 0;
01099    else
01100       user->talk.actual = user->talk.desired;
01101 }

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

Definition at line 1056 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

01057 {
01058    switch (action) {
01059    case VOL_UP:
01060       switch (vol->desired) { 
01061       case 5:
01062          break;
01063       case 0:
01064          vol->desired = 2;
01065          break;
01066       case -2:
01067          vol->desired = 0;
01068          break;
01069       default:
01070          vol->desired++;
01071          break;
01072       }
01073       break;
01074    case VOL_DOWN:
01075       switch (vol->desired) {
01076       case -5:
01077          break;
01078       case 2:
01079          vol->desired = 0;
01080          break;
01081       case 0:
01082          vol->desired = -2;
01083          break;
01084       default:
01085          vol->desired--;
01086          break;
01087       }
01088    }
01089 }

static int unload_module ( void   )  [static]

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

07427 {
07428    int res = 0;
07429    
07430    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07431    res = ast_manager_unregister("MeetmeMute");
07432    res |= ast_manager_unregister("MeetmeUnmute");
07433    res |= ast_manager_unregister("MeetmeList");
07434    res |= ast_unregister_application(app4);
07435    res |= ast_unregister_application(app3);
07436    res |= ast_unregister_application(app2);
07437    res |= ast_unregister_application(app);
07438    res |= ast_unregister_application(slastation_app);
07439    res |= ast_unregister_application(slatrunk_app);
07440 
07441 #ifdef TEST_FRAMEWORK
07442    AST_TEST_UNREGISTER(test_meetme_data_provider);
07443 #endif
07444    ast_data_unregister(NULL);
07445 
07446    ast_devstate_prov_del("Meetme");
07447    ast_devstate_prov_del("SLA");
07448    
07449    sla_destroy();
07450    
07451    res |= ast_custom_function_unregister(&meetme_info_acf);
07452    ast_unload_realtime("meetme");
07453 
07454    return res;
07455 }

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

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

07278 {
07279    struct ast_data *data_meetme_user;
07280    struct ast_data *data_meetme_user_channel;
07281    struct ast_data *data_meetme_user_volume;
07282 
07283    struct ast_conf_user *user = obj;
07284    struct ast_data *data_meetme_users = arg;
07285 
07286    data_meetme_user = ast_data_add_node(data_meetme_users, "user");
07287    if (!data_meetme_user) {
07288       return 0;
07289    }
07290    /* user structure */
07291    ast_data_add_structure(ast_conf_user, data_meetme_user, user);
07292 
07293    /* user's channel */
07294    data_meetme_user_channel = ast_data_add_node(data_meetme_user, "channel");
07295    if (!data_meetme_user_channel) {
07296       return 0;
07297    }
07298 
07299    ast_channel_data_add_structure(data_meetme_user_channel, user->chan, 1);
07300 
07301    /* volume structure */
07302    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "listen-volume");
07303    if (!data_meetme_user_volume) {
07304       return 0;
07305    }
07306    ast_data_add_int(data_meetme_user_volume, "desired", user->listen.desired);
07307    ast_data_add_int(data_meetme_user_volume, "actual", user->listen.actual);
07308 
07309    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "talk-volume");
07310    if (!data_meetme_user_volume) {
07311       return 0;
07312    }
07313    ast_data_add_int(data_meetme_user_volume, "desired", user->talk.desired);
07314    ast_data_add_int(data_meetme_user_volume, "actual", user->talk.actual);
07315 
07316    return 0;
07317 }

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

Definition at line 4741 of file app_meetme.c.

References ast_conf_user::chan, CMP_MATCH, and CMP_STOP.

Referenced by channel_admin_exec().

04742 {
04743    struct ast_conf_user *user = obj;
04744    const char *channel = args;
04745 
04746    if (!strcmp(user->chan->name, channel)) {
04747       return (CMP_MATCH | CMP_STOP);
04748    }
04749 
04750    return 0;
04751 }

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

Definition at line 4713 of file app_meetme.c.

References tweak_listen_volume(), and VOL_DOWN.

Referenced by admin_exec().

04714 {
04715    struct ast_conf_user *user = obj;
04716    tweak_listen_volume(user, VOL_DOWN);
04717    return 0;
04718 }

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

Definition at line 4706 of file app_meetme.c.

References tweak_listen_volume(), and VOL_UP.

Referenced by admin_exec().

04707 {
04708    struct ast_conf_user *user = obj;
04709    tweak_listen_volume(user, VOL_UP);
04710    return 0;
04711 }

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

Definition at line 1176 of file app_meetme.c.

References ast_conf_user::user_no.

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

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

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

Definition at line 1164 of file app_meetme.c.

References CMP_MATCH, CMP_STOP, and ast_conf_user::user_no.

Referenced by build_conf().

01165 {
01166    struct ast_conf_user *user = obj;
01167    int *user_no = arg;
01168 
01169    if (user->user_no == *user_no) {
01170       return (CMP_MATCH | CMP_STOP);
01171    }
01172 
01173    return 0;
01174 }

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

Definition at line 4734 of file app_meetme.c.

References reset_volumes().

Referenced by admin_exec().

04735 {
04736    struct ast_conf_user *user = obj;
04737    reset_volumes(user);
04738    return 0;
04739 }

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

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

02263 {
02264    struct ast_conf_user *user = obj;
02265    /* actual pointer contents of check_admin_arg is irrelevant */
02266 
02267    if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
02268       user->adminflags |= ADMINFLAG_KICKME;
02269    }
02270    return 0;
02271 }

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

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

02285 {
02286    struct ast_conf_user *user = obj;
02287    /* actual pointer contents of check_admin_arg is irrelevant */
02288 
02289    if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
02290       user->adminflags |= ADMINFLAG_MUTED;
02291    }
02292    return 0;
02293 }

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

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

02274 {
02275    struct ast_conf_user *user = obj;
02276    /* actual pointer contents of check_admin_arg is irrelevant */
02277 
02278    if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
02279       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
02280    }
02281    return 0;
02282 }

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

Definition at line 4727 of file app_meetme.c.

References tweak_talk_volume(), and VOL_DOWN.

Referenced by admin_exec().

04728 {
04729    struct ast_conf_user *user = obj;
04730    tweak_talk_volume(user, VOL_DOWN);
04731    return 0;
04732 }

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

Definition at line 4720 of file app_meetme.c.

References tweak_talk_volume(), and VOL_UP.

Referenced by admin_exec().

04721 {
04722    struct ast_conf_user *user = obj;
04723    tweak_talk_volume(user, VOL_UP);
04724    return 0;
04725 }


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

struct ast_cli_entry cli_meetme[] [static]

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

Definition at line 951 of file app_meetme.c.

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

Initial value:

Definition at line 7357 of file app_meetme.c.

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

Definition at line 7362 of file app_meetme.c.

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

Definition at line 7228 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]
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 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1