Thu Apr 28 2011 17:15:28

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 "enter.h"
#include "leave.h"
Include dependency graph for app_meetme.c:

Go to the source code of this file.

Data Structures

struct  announce_listitem
struct  ast_conf_user
 The MeetMe User object. More...
struct  ast_conference
 The MeetMe Conference object. More...
struct  confs
struct  dial_trunk_args
struct  run_station_args
struct  sla_event
struct  sla_failed_station
 A station that failed to be dialed. More...
struct  sla_ringing_station
 A station that is ringing. More...
struct  sla_ringing_trunk
 A trunk that is ringing. More...
struct  sla_station
struct  sla_station_ref
struct  sla_stations
struct  sla_trunk
struct  sla_trunk_ref
struct  sla_trunks
struct  volume

Defines

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

Enumerations

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

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

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

Functions

static void __fini_sla_stations (void)
static void __fini_sla_trunks (void)
static void __init_sla_stations (void)
static void __init_sla_trunks (void)
static void __reg_module (void)
static void __unreg_module (void)
static int acf_meetme_info (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_meetme_info_eval (char *keyword, struct ast_conference *conf)
static int action_meetmelist (struct mansession *s, const struct message *m)
static int action_meetmemute (struct mansession *s, const struct message *m)
static int action_meetmeunmute (struct mansession *s, const struct message *m)
static int admin_exec (struct ast_channel *chan, void *data)
 The MeetMeadmin application.
static void * announce_thread (void *data)
static void answer_trunk_chan (struct ast_channel *chan)
static struct ast_conferencebuild_conf (char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan)
 Find or create a conference.
static int can_write (struct ast_channel *chan, int confflags)
static int careful_write (int fd, unsigned char *data, int len, int block)
static int channel_admin_exec (struct ast_channel *chan, void *data)
static char * complete_meetmecmd (const char *line, const char *word, int pos, int state)
static int conf_exec (struct ast_channel *chan, void *data)
 The meetme() application.
static void conf_flush (int fd, struct ast_channel *chan)
static int conf_free (struct ast_conference *conf)
static void conf_play (struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
static void conf_queue_dtmf (const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
static int conf_run (struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
static void conf_start_moh (struct ast_channel *chan, const char *musicclass)
static int count_exec (struct ast_channel *chan, void *data)
 The MeetmeCount application.
static struct sla_trunk_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)
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_flags *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_flags *confflags, int *too_early, char **optargs)
static struct ast_conf_userfind_user (struct ast_conference *conf, char *callerident)
static const char * get_announce_filename (enum announcetypes type)
static char * istalking (int x)
static int load_config (int reload)
static void load_config_meetme (void)
static int load_module (void)
static char * meetme_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static 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 (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, void *data)
static void sla_stop_ringing_station (struct sla_ringing_station *ringing_station, enum sla_station_hangup hangup)
static void sla_stop_ringing_trunk (struct sla_ringing_trunk *ringing_trunk)
static void * sla_thread (void *data)
static int sla_trunk_exec (struct ast_channel *chan, void *data)
static const char * trunkstate2str (enum sla_trunk_state state)
static void tweak_listen_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_talk_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_volume (struct volume *vol, enum volume_action action)
static int unload_module (void)
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 *unused, int flags)
static int user_set_muted_cb (void *obj, void *unused, int flags)
static int user_set_unmuted_cb (void *obj, void *unused, int flags)
static int user_talk_voldown_cb (void *obj, void *unused, int flags)
static int user_talk_volup_cb (void *obj, void *unused, int flags)

Variables

static struct ast_module_info
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "MeetMe conference bridge" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static const char * app = "MeetMe"
static const char * app2 = "MeetMeCount"
static const char * app3 = "MeetMeAdmin"
static const char * app4 = "MeetMeChannelAdmin"
static struct ast_module_infoast_module_info = &__mod_info
static int audio_buffers
static struct ast_cli_entry cli_meetme []
static unsigned int conf_map [1024] = {0, }
static struct confs confs
static int earlyalert
static int endalert
static int extendby
static int fuzzystart
static char const gain_map []
static char mandescr_meetmelist [] = " *Conference: <confno>\n"
static struct ast_custom_function meetme_info_acf
static struct ast_app_option meetme_opts [128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
static int rt_log_members
static int rt_schedule
struct {
   unsigned int   attempt_callerid:1
   ast_cond_t   cond
   struct {
      struct sla_event *   first
      struct sla_event *   last
   }   event_q
   struct {
      struct sla_failed_station *   first
      struct sla_failed_station *   last
   }   failed_stations
   ast_mutex_t   lock
   unsigned int   reload:1
   struct {
      struct sla_ringing_station *   first
      struct sla_ringing_station *   last
   }   ringing_stations
   struct {
      struct sla_ringing_trunk *   first
      struct sla_ringing_trunk *   last
   }   ringing_trunks
   unsigned int   stop:1
   pthread_t   thread
sla
static const char sla_registrar [] = "SLA"
static struct sla_stations sla_stations
static struct ast_app_option sla_trunk_opts [128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, }
static struct sla_trunks sla_trunks
static const char * slastation_app = "SLAStation"
static const char * 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 445 of file app_meetme.c.

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

#define CONF_SIZE   320

Definition at line 464 of file app_meetme.c.

Referenced by conf_run().

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 425 of file app_meetme.c.

Referenced by 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 432 of file app_meetme.c.

Referenced by conf_run(), find_conf_realtime(), and rt_extend_conf().

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 429 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80
#define MAX_PIN   80

Definition at line 586 of file app_meetme.c.

Referenced by conf_exec().

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

Definition at line 590 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_DELAYDETECTENDTALK   1000

Definition at line 443 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 442 of file app_meetme.c.

Referenced by conf_run().

#define OPTIONS_LEN   100

Definition at line 587 of file app_meetme.c.

Referenced by find_conf_realtime().

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

Referenced by sms_readfile(), and trunkstate2str().

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 426 of file app_meetme.c.

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


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

     {
   ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
   ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
   ADMINFLAG_KICKME =    (1 << 3),  /*!< User has been kicked */
   /*! User has requested to speak */
   ADMINFLAG_T_REQUEST = (1 << 4),
};
anonymous enum
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 MeetMe will return if all marked with this flag left

CONFFLAG_WAITMARKED 

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

CONFFLAG_EXIT_CONTEXT 

If set, the MeetMe will exit to the specified context

CONFFLAG_MARKEDUSER 

If set, the user will be marked

CONFFLAG_INTROUSER 

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

CONFFLAG_RECORDCONF 

If set, the MeetMe will be recorded

CONFFLAG_MONITORTALKER 

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

CONFFLAG_DYNAMIC 
CONFFLAG_DYNAMICPIN 
CONFFLAG_EMPTY 
CONFFLAG_EMPTYNOPIN 
CONFFLAG_ALWAYSPROMPT 
CONFFLAG_OPTIMIZETALKER 

If set, treat talking users as muted users

CONFFLAG_NOONLYPERSON 

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

CONFFLAG_INTROUSERNOREVIEW 

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

CONFFLAG_STARTMUTED 

If set, the user will be initially self-muted

CONFFLAG_PASS_DTMF 

Pass DTMF through the conference

CONFFLAG_SLA_STATION 
CONFFLAG_SLA_TRUNK 
CONFFLAG_KICK_CONTINUE 

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

CONFFLAG_DURATION_STOP 
CONFFLAG_DURATION_LIMIT 
CONFFLAG_NO_AUDIO_UNTIL_UP 

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

Definition at line 466 of file app_meetme.c.

     {
   /*! user has admin access on the conference */
   CONFFLAG_ADMIN = (1 << 0),
   /*! If set the user can only receive audio from the conference */
   CONFFLAG_MONITOR = (1 << 1),
   /*! If set asterisk will exit conference when key defined in p() option is pressed */
   CONFFLAG_KEYEXIT = (1 << 2),
   /*! If set asterisk will provide a menu to the user when '*' is pressed */
   CONFFLAG_STARMENU = (1 << 3),
   /*! If set the use can only send audio to the conference */
   CONFFLAG_TALKER = (1 << 4),
   /*! If set there will be no enter or leave sounds */
   CONFFLAG_QUIET = (1 << 5),
   /*! If set, when user joins the conference, they will be told the number 
    *  of users that are already in */
   CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
   /*! Set to run AGI Script in Background */
   CONFFLAG_AGI = (1 << 7),
   /*! Set to have music on hold when user is alone in conference */
   CONFFLAG_MOH = (1 << 8),
   /*! If set the MeetMe will return if all marked with this flag left */
   CONFFLAG_MARKEDEXIT = (1 << 9),
   /*! If set, the MeetMe will wait until a marked user enters */
   CONFFLAG_WAITMARKED = (1 << 10),
   /*! If set, the MeetMe will exit to the specified context */
   CONFFLAG_EXIT_CONTEXT = (1 << 11),
   /*! If set, the user will be marked */
   CONFFLAG_MARKEDUSER = (1 << 12),
   /*! If set, user will be ask record name on entry of conference */
   CONFFLAG_INTROUSER = (1 << 13),
   /*! If set, the MeetMe will be recorded */
   CONFFLAG_RECORDCONF = (1<< 14),
   /*! If set, the user will be monitored if the user is talking or not */
   CONFFLAG_MONITORTALKER = (1 << 15),
   CONFFLAG_DYNAMIC = (1 << 16),
   CONFFLAG_DYNAMICPIN = (1 << 17),
   CONFFLAG_EMPTY = (1 << 18),
   CONFFLAG_EMPTYNOPIN = (1 << 19),
   CONFFLAG_ALWAYSPROMPT = (1 << 20),
   /*! If set, treat talking users as muted users */
   CONFFLAG_OPTIMIZETALKER = (1 << 21),
   /*! If set, won't speak the extra prompt when the first person 
    *  enters the conference */
   CONFFLAG_NOONLYPERSON = (1 << 22),
   /*! If set, user will be asked to record name on entry of conference 
    *  without review */
   CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
   /*! If set, the user will be initially self-muted */
   CONFFLAG_STARTMUTED = (1 << 24),
   /*! Pass DTMF through the conference */
   CONFFLAG_PASS_DTMF = (1 << 25),
   CONFFLAG_SLA_STATION = (1 << 26),
   CONFFLAG_SLA_TRUNK = (1 << 27),
   /*! If set, the user should continue in the dialplan if kicked out */
   CONFFLAG_KICK_CONTINUE = (1 << 28),
   CONFFLAG_DURATION_STOP = (1 << 29),
   CONFFLAG_DURATION_LIMIT = (1 << 30),
   /*! Do not write any audio to this channel until the state is up. */
   CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31),
};
anonymous enum
Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_EXITKEYS 
OPT_ARG_DURATION_STOP 
OPT_ARG_DURATION_LIMIT 
OPT_ARG_MOH_CLASS 
OPT_ARG_ARRAY_SIZE 

Definition at line 527 of file app_meetme.c.

anonymous enum
Enumerator:
SLA_TRUNK_OPT_MOH 

Definition at line 5992 of file app_meetme.c.

     {
   SLA_TRUNK_OPT_MOH = (1 << 0),
};
anonymous enum
Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 5996 of file app_meetme.c.

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 592 of file app_meetme.c.

Enumerator:
ENTER 
LEAVE 

Definition at line 452 of file app_meetme.c.

                    {
   ENTER,
   LEAVE
};
Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

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

                    {
   /*! A station has put the call on hold */
   SLA_EVENT_HOLD,
   /*! The state of a dial has changed */
   SLA_EVENT_DIAL_STATE,
   /*! The state of a ringing trunk has changed */
   SLA_EVENT_RINGING_TRUNK,
   /*! A reload of configuration has been requested */
   SLA_EVENT_RELOAD,
   /*! Poke the SLA thread so it can check if it can perform a reload */
   SLA_EVENT_CHECK_RELOAD,
};
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 695 of file app_meetme.c.

                     {
   /*! This means that any station can put it on hold, and any station
    * can retrieve the call from hold. */
   SLA_HOLD_OPEN,
   /*! This means that only the station that put the call on hold may
    * retrieve it from hold. */
   SLA_HOLD_PRIVATE,
};
Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

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

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 682 of file app_meetme.c.

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 447 of file app_meetme.c.


Function Documentation

static void __fini_sla_stations ( void  ) [static]

Definition at line 779 of file app_meetme.c.

{
static void __fini_sla_trunks ( void  ) [static]

Definition at line 780 of file app_meetme.c.

{
static void __init_sla_stations ( void  ) [static]

Definition at line 779 of file app_meetme.c.

{
static void __init_sla_trunks ( void  ) [static]

Definition at line 780 of file app_meetme.c.

{
static void __reg_module ( void  ) [static]

Definition at line 6699 of file app_meetme.c.

static void __unreg_module ( void  ) [static]

Definition at line 6699 of file app_meetme.c.

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

Definition at line 6554 of file app_meetme.c.

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

{
   struct ast_conference *conf;
   char *parse;
   int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(keyword);
      AST_APP_ARG(confno);
   );

   if (ast_strlen_zero(data)) {
      ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
      return -1;
   }

   parse = ast_strdupa(data);
   AST_STANDARD_APP_ARGS(args, parse);

   if (ast_strlen_zero(args.keyword)) {
      ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
      return -1;
   }

   if (ast_strlen_zero(args.confno)) {
      ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
      return -1;
   }

   AST_LIST_LOCK(&confs);
   AST_LIST_TRAVERSE(&confs, conf, list) {
      if (!strcmp(args.confno, conf->confno)) {
         result = acf_meetme_info_eval(args.keyword, conf);
         break;
      }
   }
   AST_LIST_UNLOCK(&confs);

   if (result > -1) {
      snprintf(buf, len, "%d", result);
   } else if (result == -1) {
      ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
      snprintf(buf, len, "0");
   } else if (result == -2) {
      ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno); 
      snprintf(buf, len, "0");
   }

   return 0;
}
static int acf_meetme_info_eval ( char *  keyword,
struct ast_conference conf 
) [static]

Definition at line 6536 of file app_meetme.c.

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

Referenced by acf_meetme_info().

{
   if (!strcasecmp("lock", keyword)) {
      return conf->locked;
   } else if (!strcasecmp("parties", keyword)) {
      return conf->users;
   } else if (!strcasecmp("activity", keyword)) {
      time_t now;
      now = time(NULL);
      return (now - conf->start);
   } else if (!strcasecmp("dynamic", keyword)) {
      return conf->isdynamic;
   } else {
      return -1;
   }

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

Definition at line 4471 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(), astman_append(), astman_get_header(), astman_send_error(), astman_send_listack(), ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CONFFLAG_ADMIN, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_conference::confno, ast_channel::name, S_OR, ast_conf_user::talking, total, user, ast_conf_user::user_no, ast_conference::usercontainer, and ast_conf_user::userflags.

Referenced by load_module().

{
   const char *actionid = astman_get_header(m, "ActionID");
   const char *conference = astman_get_header(m, "Conference");
   char idText[80] = "";
   struct ast_conference *cnf;
   struct ast_conf_user *user;
   struct ao2_iterator user_iter;
   int total = 0;

   if (!ast_strlen_zero(actionid))
      snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);

   if (AST_LIST_EMPTY(&confs)) {
      astman_send_error(s, m, "No active conferences.");
      return 0;
   }

   astman_send_listack(s, m, "Meetme user list will follow", "start");

   /* Find the right conference */
   AST_LIST_LOCK(&confs);
   AST_LIST_TRAVERSE(&confs, cnf, list) {
      user_iter = ao2_iterator_init(cnf->usercontainer, 0);
      /* If we ask for one particular, and this isn't it, skip it */
      if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
         continue;

      /* Show all the users */
      while ((user = ao2_iterator_next(&user_iter))) {
         total++;
         astman_append(s,
         "Event: MeetmeList\r\n"
         "%s"
         "Conference: %s\r\n"
         "UserNumber: %d\r\n"
         "CallerIDNum: %s\r\n"
         "CallerIDName: %s\r\n"
         "Channel: %s\r\n"
         "Admin: %s\r\n"
         "Role: %s\r\n"
         "MarkedUser: %s\r\n"
         "Muted: %s\r\n"
         "Talking: %s\r\n"
         "\r\n",
         idText,
         cnf->confno,
         user->user_no,
         S_OR(user->chan->cid.cid_num, "<unknown>"),
         S_OR(user->chan->cid.cid_name, "<no name>"),
         user->chan->name,
         user->userflags & CONFFLAG_ADMIN ? "Yes" : "No",
         user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen",
         user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No",
         user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
         user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
         ao2_ref(user, -1); 
      }
      ao2_iterator_destroy(&user_iter);
   }
   AST_LIST_UNLOCK(&confs);
   /* Send final confirmation */
   astman_append(s,
   "Event: MeetmeListComplete\r\n"
   "EventList: Complete\r\n"
   "ListItems: %d\r\n"
   "%s"
   "\r\n", total, idText);
   return 0;
}
static int action_meetmemute ( struct mansession s,
const struct message m 
) [static]

Definition at line 4453 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

{
   return meetmemute(s, m, 1);
}
static int action_meetmeunmute ( struct mansession s,
const struct message m 
) [static]

Definition at line 4458 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

{
   return meetmemute(s, m, 0);
}
static int admin_exec ( struct ast_channel chan,
void *  data 
) [static]

The MeetMeadmin application.

Definition at line 4186 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, 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(), CONFFLAG_ADMIN, ast_conference::confno, dispose_conf(), find_user(), ast_conf_user::list, 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(), meetme_show_cmd(), run_station(), sla_station_exec(), and sla_stop_ringing_trunk().

                                                            {
   char *params;
   struct ast_conference *cnf;
   struct ast_conf_user *user = NULL;
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(confno);
      AST_APP_ARG(command);
      AST_APP_ARG(user);
   );
   int res = 0;

   if (ast_strlen_zero(data)) {
      ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
      pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
      return -1;
   }

   params = ast_strdupa(data);
   AST_STANDARD_APP_ARGS(args, params);

   if (!args.command) {
      ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
      pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
      return -1;
   }

   AST_LIST_LOCK(&confs);
   AST_LIST_TRAVERSE(&confs, cnf, list) {
      if (!strcmp(cnf->confno, args.confno))
         break;
   }

   if (!cnf) {
      ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
      AST_LIST_UNLOCK(&confs);
      pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
      return 0;
   }

   ast_atomic_fetchadd_int(&cnf->refcount, 1);

   if (args.user) {
      user = find_user(cnf, args.user);
      if (!user) {
         ast_log(LOG_NOTICE, "Specified User not found!\n");
         res = -2;
         goto usernotfound;
      }
   }

   switch (*args.command) {
   case 76: /* L: Lock */ 
      cnf->locked = 1;
      break;
   case 108: /* l: Unlock */ 
      cnf->locked = 0;
      break;
   case 75: /* K: kick all users */
      ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_kickme_cb, NULL);
      break;
   case 101: /* e: Eject last user*/
   {
      int max_no = 0;
      ao2_callback(cnf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
      user = ao2_find(cnf->usercontainer, &max_no, 0);
      if (!(user->userflags & CONFFLAG_ADMIN))
         user->adminflags |= ADMINFLAG_KICKME;
      else {
         res = -1;
         ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
      }
      ao2_ref(user, -1);
      break;
   }
   case 77: /* M: Mute */ 
      if (user) {
         user->adminflags |= ADMINFLAG_MUTED;
      } else {
         res = -2;
         ast_log(LOG_NOTICE, "Specified User not found!\n");
      }
      break;
   case 78: /* N: Mute all (non-admin) users */
      ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_muted_cb, NULL);
      break;               
   case 109: /* m: Unmute */ 
      user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
      break;
   case 110: /* n: Unmute all users */
      ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, NULL);
      break;
   case 107: /* k: Kick user */ 
      user->adminflags |= ADMINFLAG_KICKME;
      break;
   case 118: /* v: Lower all users listen volume */
      ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_voldown_cb, NULL);
      break;
   case 86: /* V: Raise all users listen volume */
      ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_volup_cb, NULL);
      break;
   case 115: /* s: Lower all users speaking volume */
      ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_voldown_cb, NULL);
      break;
   case 83: /* S: Raise all users speaking volume */
      ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_volup_cb, NULL);
      break;
   case 82: /* R: Reset all volume levels */
      ao2_callback(cnf->usercontainer, OBJ_NODATA, user_reset_vol_cb, NULL);
      break;
   case 114: /* r: Reset user's volume level */
      reset_volumes(user);
      break;
   case 85: /* U: Raise user's listen volume */
      tweak_listen_volume(user, VOL_UP);
      break;
   case 117: /* u: Lower user's listen volume */
      tweak_listen_volume(user, VOL_DOWN);
      break;
   case 84: /* T: Raise user's talk volume */
      tweak_talk_volume(user, VOL_UP);
      break;
   case 116: /* t: Lower user's talk volume */
      tweak_talk_volume(user, VOL_DOWN);
      break;
   case 'E': /* E: Extend conference */
      if (rt_extend_conf(args.confno)) {
         res = -1;
      }
      break;
   }

   if (args.user) {
      /* decrement reference from find_user */
      ao2_ref(user, -1);
   }
usernotfound:
   AST_LIST_UNLOCK(&confs);

   dispose_conf(cnf);
   pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");

   return 0;
}
static void* announce_thread ( void *  data) [static]

Definition at line 1961 of file app_meetme.c.

References ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread_stop, announce_listitem::announcetype, ao2_ref, ast_check_hangup(), ast_cond_wait(), ast_copy_string(), ast_filedelete(), ast_fileexists(), AST_LIST_APPEND_LIST, AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_REMOVE_HEAD, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_streamfile(), ast_waitstream(), CONF_HASLEFT, announce_listitem::confchan, announce_listitem::confusers, get_announce_filename(), announce_listitem::language, LOG_DEBUG, and announce_listitem::namerecloc.

Referenced by conf_run().

{
   struct announce_listitem *current;
   struct ast_conference *conf = data;
   int res;
   char filename[PATH_MAX] = "";
   AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
   AST_LIST_HEAD_INIT_NOLOCK(&local_list);

   while (!conf->announcethread_stop) {
      ast_mutex_lock(&conf->announcelistlock);
      if (conf->announcethread_stop) {
         ast_mutex_unlock(&conf->announcelistlock);
         break;
      }
      if (AST_LIST_EMPTY(&conf->announcelist))
         ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);

      AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
      AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);

      ast_mutex_unlock(&conf->announcelistlock);
      if (conf->announcethread_stop) {
         break;
      }

      for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
         ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
         if (!ast_fileexists(current->namerecloc, NULL, NULL))
            continue;
         if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
            if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
               res = ast_waitstream(current->confchan, "");
            if (!res) {
               ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
               if (!ast_streamfile(current->confchan, filename, current->language))
                  ast_waitstream(current->confchan, "");
            }
         }
         if (current->announcetype == CONF_HASLEFT) {
            ast_filedelete(current->namerecloc, NULL);
         }
      }
   }

   /* thread marked to stop, clean up */
   while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
      ast_filedelete(current->namerecloc, NULL);
      ao2_ref(current, -1);
   }
   return NULL;
}
static void answer_trunk_chan ( struct ast_channel chan) [static]

Definition at line 4850 of file app_meetme.c.

References ast_answer(), and ast_indicate().

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

{
   ast_answer(chan);
   ast_indicate(chan, -1);
}
static struct ast_conference* build_conf ( char *  confno,
char *  pin,
char *  pinadmin,
int  make,
int  dynamic,
int  refcount,
const struct ast_channel chan 
) [static, read]

Find or create a conference.

Parameters:
confnoThe conference name/number
pinThe regular user pin
pinadminThe admin pin
makeMake the conf if it doesn't exist
dynamicMark the newly created conference as dynamic
refcountHow many references to mark on the conference
chanThe 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 1085 of file app_meetme.c.

References ast_conference::announcethread, ast_conference::announcethreadlock, 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_verb, ast_conference::chan, conf_map, ast_conference::confno, ast_conference::dahdiconf, ast_conference::fd, ast_channel::fds, ast_conference::isdynamic, ast_conference::listenlock, LOG_WARNING, ast_conference::maxusers, ast_conference::pin, ast_conference::pinadmin, ast_conference::playlock, ast_conference::recordthread, ast_conference::recordthreadlock, ast_conference::refcount, ast_conference::start, ast_channel::uniqueid, 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().

{
   struct ast_conference *cnf;
   struct dahdi_confinfo dahdic = { 0, };
   int confno_int = 0;

   AST_LIST_LOCK(&confs);

   AST_LIST_TRAVERSE(&confs, cnf, list) {
      if (!strcmp(confno, cnf->confno)) 
         break;
   }

   if (cnf || (!make && !dynamic))
      goto cnfout;

   /* Make a new one */
   if (!(cnf = ast_calloc(1, sizeof(*cnf))) ||
      !(cnf->usercontainer = ao2_container_alloc(1, NULL, user_no_cmp))) {
      goto cnfout;
   }

   ast_mutex_init(&cnf->playlock);
   ast_mutex_init(&cnf->listenlock);
   cnf->recordthread = AST_PTHREADT_NULL;
   ast_mutex_init(&cnf->recordthreadlock);
   cnf->announcethread = AST_PTHREADT_NULL;
   ast_mutex_init(&cnf->announcethreadlock);
   ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
   ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
   ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
   ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid));

   /* Setup a new dahdi conference */
   dahdic.confno = -1;
   dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
   cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
   if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
      ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
      if (cnf->fd >= 0)
         close(cnf->fd);
      ao2_ref(cnf->usercontainer, -1);
      ast_mutex_destroy(&cnf->playlock);
      ast_mutex_destroy(&cnf->listenlock);
      ast_mutex_destroy(&cnf->recordthreadlock);
      ast_mutex_destroy(&cnf->announcethreadlock);
      ast_free(cnf);
      cnf = NULL;
      goto cnfout;
   }

   cnf->dahdiconf = dahdic.confno;

   /* Setup a new channel for playback of audio files */
   cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL);
   if (cnf->chan) {
      ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
      ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
      dahdic.chan = 0;
      dahdic.confno = cnf->dahdiconf;
      dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
      if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
         ast_log(LOG_WARNING, "Error setting conference\n");
         if (cnf->chan)
            ast_hangup(cnf->chan);
         else
            close(cnf->fd);
         ao2_ref(cnf->usercontainer, -1);
         ast_mutex_destroy(&cnf->playlock);
         ast_mutex_destroy(&cnf->listenlock);
         ast_mutex_destroy(&cnf->recordthreadlock);
         ast_mutex_destroy(&cnf->announcethreadlock);
         ast_free(cnf);
         cnf = NULL;
         goto cnfout;
      }
   }

   /* Fill the conference struct */
   cnf->start = time(NULL);
   cnf->maxusers = 0x7fffffff;
   cnf->isdynamic = dynamic ? 1 : 0;
   ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
   AST_LIST_INSERT_HEAD(&confs, cnf, list);

   /* Reserve conference number in map */
   if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
      conf_map[confno_int] = 1;
   
cnfout:
   if (cnf)
      ast_atomic_fetchadd_int(&cnf->refcount, refcount);

   AST_LIST_UNLOCK(&confs);

   return cnf;
}
static int can_write ( struct ast_channel chan,
int  confflags 
) [static]

Definition at line 2014 of file app_meetme.c.

References ast_channel::_state, AST_STATE_UP, and CONFFLAG_NO_AUDIO_UNTIL_UP.

Referenced by conf_run().

{
   if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
      return 1;
   }

   return (chan->_state == AST_STATE_UP);
}
static int careful_write ( int  fd,
unsigned char *  data,
int  len,
int  block 
) [static]

Definition at line 895 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

Referenced by conf_play(), and conf_run().

{
   int res;
   int x;

   while (len) {
      if (block) {
         x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
         res = ioctl(fd, DAHDI_IOMUX, &x);
      } else
         res = 0;
      if (res >= 0)
         res = write(fd, data, len);
      if (res < 1) {
         if (errno != EAGAIN) {
            ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
            return -1;
         } else
            return 0;
      }
      len -= res;
      data += res;
   }

   return 0;
}
static int channel_admin_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 4332 of file app_meetme.c.

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

Referenced by load_module().

                                                                    {
   char *params;
   struct ast_conference *conf = NULL;
   struct ast_conf_user *user = NULL;
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(channel);
      AST_APP_ARG(command);
   );

   if (ast_strlen_zero(data)) {
      ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
      return -1;
   }
   
   params = ast_strdupa(data);
   AST_STANDARD_APP_ARGS(args, params);

   if (!args.channel) {
      ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
      return -1;
   }

   if (!args.command) {
      ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
      return -1;
   }

   AST_LIST_LOCK(&confs);
   AST_LIST_TRAVERSE(&confs, conf, list) {
      if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
         break;
      }
   }
   
   if (!user) {
      ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
      AST_LIST_UNLOCK(&confs);
      return 0;
   }
   
   /* perform the specified action */
   switch (*args.command) {
      case 77: /* M: Mute */ 
         user->adminflags |= ADMINFLAG_MUTED;
         break;
      case 109: /* m: Unmute */ 
         user->adminflags &= ~ADMINFLAG_MUTED;
         break;
      case 107: /* k: Kick user */ 
         user->adminflags |= ADMINFLAG_KICKME;
         break;
      default: /* unknown command */
         ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
         break;
   }
   ao2_ref(user, -1);
   AST_LIST_UNLOCK(&confs);
   
   return 0;
}
static char* complete_meetmecmd ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 1183 of file app_meetme.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_cli_complete(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_strdupa, ast_conference::confno, len(), ast_conf_user::list, strsep(), ast_conf_user::user_no, and ast_conference::usercontainer.

Referenced by meetme_cmd(), and meetme_show_cmd().

{
   static char *cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};

   int len = strlen(word);
   int which = 0;
   struct ast_conference *cnf = NULL;
   struct ast_conf_user *usr = NULL;
   char *confno = NULL;
   char usrno[50] = "";
   char *myline, *ret = NULL;
   
   if (pos == 1) {      /* Command */
      return ast_cli_complete(word, cmds, state);
   } else if (pos == 2) {  /* Conference Number */
      AST_LIST_LOCK(&confs);
      AST_LIST_TRAVERSE(&confs, cnf, list) {
         if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
            ret = cnf->confno;
            break;
         }
      }
      ret = ast_strdup(ret); /* dup before releasing the lock */
      AST_LIST_UNLOCK(&confs);
      return ret;
   } else if (pos == 3) {
      /* User Number || Conf Command option*/
      if (strstr(line, "mute") || strstr(line, "kick")) {
         if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
            return ast_strdup("all");
         which++;
         AST_LIST_LOCK(&confs);

         /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
         myline = ast_strdupa(line);
         if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
            while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
               ;
         }
         
         AST_LIST_TRAVERSE(&confs, cnf, list) {
            if (!strcmp(confno, cnf->confno))
                break;
         }

         if (cnf) {
            struct ao2_iterator user_iter;
            user_iter = ao2_iterator_init(cnf->usercontainer, 0);
            /* Search for the user */
            while((usr = ao2_iterator_next(&user_iter))) {
               snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
               if (!strncasecmp(word, usrno, len) && ++which > state) {
                  ao2_ref(usr, -1);
                  break;
               }
               ao2_ref(usr, -1);
            }
            ao2_iterator_destroy(&user_iter);
            AST_LIST_UNLOCK(&confs);
            return usr ? ast_strdup(usrno) : NULL;
         }
      }
   }

   return NULL;
}
static int conf_exec ( struct ast_channel chan,
void *  data 
) [static]

The meetme() application.

Definition at line 3795 of file app_meetme.c.

References ast_channel::_state, ast_conference::adminopts, ARRAY_LEN, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options(), ast_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_flag, 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_flags, CONFIG_STATUS_FILEINVALID, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), ast_flags::flags, ast_conference::isdynamic, ast_channel::language, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, MAX_SETTINGS, meetme_opts, ast_variable::name, ast_variable::next, OPT_ARG_ARRAY_SIZE, parse(), ast_conference::pin, ast_conference::pinadmin, ast_conference::recordingfilename, ast_conference::recordingformat, SENTINEL, strsep(), ast_conference::useropts, ast_conference::users, ast_variable::value, and var.

Referenced by load_module().

{
   int res = -1;
   char confno[MAX_CONFNUM] = "";
   int allowretry = 0;
   int retrycnt = 0;
   struct ast_conference *cnf = NULL;
   struct ast_flags confflags = {0}, config_flags = { 0 };
   int dynamic = 0;
   int empty = 0, empty_no_pin = 0;
   int always_prompt = 0;
   char *notdata, *info, the_pin[MAX_PIN] = "";
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(confno);
      AST_APP_ARG(options);
      AST_APP_ARG(pin);
   );
   char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };

   if (ast_strlen_zero(data)) {
      allowretry = 1;
      notdata = "";
   } else {
      notdata = data;
   }
   
   if (chan->_state != AST_STATE_UP)
      ast_answer(chan);

   info = ast_strdupa(notdata);

   AST_STANDARD_APP_ARGS(args, info);  

   if (args.confno) {
      ast_copy_string(confno, args.confno, sizeof(confno));
      if (ast_strlen_zero(confno)) {
         allowretry = 1;
      }
   }
   
   if (args.pin)
      ast_copy_string(the_pin, args.pin, sizeof(the_pin));

   if (args.options) {
      ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
      dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
      if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
         strcpy(the_pin, "q");

      empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
      empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
      always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
   }

   do {
      if (retrycnt > 3)
         allowretry = 0;
      if (empty) {
         int i;
         struct ast_config *cfg;
         struct ast_variable *var;
         int confno_int;

         /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
         if ((empty_no_pin) || (!dynamic)) {
            cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
            if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
               var = ast_variable_browse(cfg, "rooms");
               while (var) {
                  char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
                  if (!strcasecmp(var->name, "conf")) {
                     int found = 0;
                     ast_copy_string(parse, var->value, sizeof(parse));
                     confno_tmp = strsep(&stringp, "|,");
                     if (!dynamic) {
                        /* For static:  run through the list and see if this conference is empty */
                        AST_LIST_LOCK(&confs);
                        AST_LIST_TRAVERSE(&confs, cnf, list) {
                           if (!strcmp(confno_tmp, cnf->confno)) {
                              /* The conference exists, therefore it's not empty */
                              found = 1;
                              break;
                           }
                        }
                        AST_LIST_UNLOCK(&confs);
                        if (!found) {
                           /* At this point, we have a confno_tmp (static conference) that is empty */
                           if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
                              /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
                               * Case 2:  empty_no_pin and pin is blank (but not NULL)
                               * Case 3:  not empty_no_pin
                               */
                              ast_copy_string(confno, confno_tmp, sizeof(confno));
                              break;
                           }
                        }
                     }
                  }
                  var = var->next;
               }
               ast_config_destroy(cfg);
            }

            if (ast_strlen_zero(confno) && (cfg = ast_load_realtime_multientry("meetme", "confno LIKE", "%", SENTINEL))) {
               const char *catg;
               for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
                  const char *confno_tmp = ast_variable_retrieve(cfg, catg, "confno");
                  const char *pin_tmp = ast_variable_retrieve(cfg, catg, "pin");
                  if (ast_strlen_zero(confno_tmp)) {
                     continue;
                  }
                  if (!dynamic) {
                     int found = 0;
                     /* For static:  run through the list and see if this conference is empty */
                     AST_LIST_LOCK(&confs);
                     AST_LIST_TRAVERSE(&confs, cnf, list) {
                        if (!strcmp(confno_tmp, cnf->confno)) {
                           /* The conference exists, therefore it's not empty */
                           found = 1;
                           break;
                        }
                     }
                     AST_LIST_UNLOCK(&confs);
                     if (!found) {
                        /* At this point, we have a confno_tmp (realtime conference) that is empty */
                        if ((empty_no_pin && ast_strlen_zero(pin_tmp)) || (!empty_no_pin)) {
                           /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
                            * Case 2:  empty_no_pin and pin is blank (but not NULL)
                            * Case 3:  not empty_no_pin
                            */
                           ast_copy_string(confno, confno_tmp, sizeof(confno));
                           break;
                        }
                     }
                  }
               }
               ast_config_destroy(cfg);
            }
         }

         /* Select first conference number not in use */
         if (ast_strlen_zero(confno) && dynamic) {
            AST_LIST_LOCK(&confs);
            for (i = 0; i < ARRAY_LEN(conf_map); i++) {
               if (!conf_map[i]) {
                  snprintf(confno, sizeof(confno), "%d", i);
                  conf_map[i] = 1;
                  break;
               }
            }
            AST_LIST_UNLOCK(&confs);
         }

         /* Not found? */
         if (ast_strlen_zero(confno)) {
            res = ast_streamfile(chan, "conf-noempty", chan->language);
            if (!res)
               ast_waitstream(chan, "");
         } else {
            if (sscanf(confno, "%30d", &confno_int) == 1) {
               if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
                  res = ast_streamfile(chan, "conf-enteringno", chan->language);
                  if (!res) {
                     ast_waitstream(chan, "");
                     res = ast_say_digits(chan, confno_int, "", chan->language);
                  }
               }
            } else {
               ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
            }
         }
      }

      while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
         /* Prompt user for conference number */
         res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
         if (res < 0) {
            /* Don't try to validate when we catch an error */
            confno[0] = '\0';
            allowretry = 0;
            break;
         }
      }
      if (!ast_strlen_zero(confno)) {
         /* Check the validity of the conference */
         cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
            sizeof(the_pin), 1, &confflags);
         if (!cnf) {
            int too_early = 0;

            cnf = find_conf_realtime(chan, confno, 1, dynamic, 
               the_pin, sizeof(the_pin), 1, &confflags, &too_early, optargs);
            if (rt_schedule && too_early)
               allowretry = 0;
         }

         if (!cnf) {
            if (allowretry) {
               confno[0] = '\0';
               res = ast_streamfile(chan, "conf-invalid", chan->language);
               if (!res)
                  ast_waitstream(chan, "");
               res = -1;
            }
         } else {
            if (((!ast_strlen_zero(cnf->pin)       &&
               !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
                 (!ast_strlen_zero(cnf->pinadmin)  &&
                   ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
                    (!ast_strlen_zero(cnf->pin) &&
                      ast_strlen_zero(cnf->pinadmin) &&
                      ast_test_flag(&confflags, CONFFLAG_ADMIN))) &&
                (!(cnf->users == 0 && cnf->isdynamic))) {
               char pin[MAX_PIN] = "";
               int j;

               /* Allow the pin to be retried up to 3 times */
               for (j = 0; j < 3; j++) {
                  if (*the_pin && (always_prompt == 0)) {
                     ast_copy_string(pin, the_pin, sizeof(pin));
                     res = 0;
                  } else {
                     /* Prompt user for pin if pin is required */
                     res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
                  }
                  if (res >= 0) {
                     if ((!strcasecmp(pin, cnf->pin) &&
                          (ast_strlen_zero(cnf->pinadmin) ||
                           !ast_test_flag(&confflags, CONFFLAG_ADMIN))) ||
                          (!ast_strlen_zero(cnf->pinadmin) &&
                           !strcasecmp(pin, cnf->pinadmin))) {
                        /* Pin correct */
                        allowretry = 0;
                        if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
                           if (!ast_strlen_zero(cnf->adminopts)) {
                              char *opts = ast_strdupa(cnf->adminopts);
                              ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
                           }
                        } else {
                           if (!ast_strlen_zero(cnf->useropts)) {
                              char *opts = ast_strdupa(cnf->useropts);
                              ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
                           }
                        }
                        /* Run the conference */
                        ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
                        res = conf_run(chan, cnf, confflags.flags, optargs);
                        break;
                     } else {
                        /* Pin invalid */
                        if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
                           res = ast_waitstream(chan, AST_DIGIT_ANY);
                           ast_stopstream(chan);
                        } else {
                           ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
                           break;
                        }
                        if (res < 0)
                           break;
                        pin[0] = res;
                        pin[1] = '\0';
                        res = -1;
                        if (allowretry)
                           confno[0] = '\0';
                     }
                  } else {
                     /* failed when getting the pin */
                     res = -1;
                     allowretry = 0;
                     /* see if we need to get rid of the conference */
                     break;
                  }

                  /* Don't retry pin with a static pin */
                  if (*the_pin && (always_prompt == 0)) {
                     break;
                  }
               }
            } else {
               /* No pin required */
               allowretry = 0;

               /* For RealTime conferences without a pin 
                * should still support loading options
                */
               if (!ast_strlen_zero(cnf->useropts)) {
                  char *opts = ast_strdupa(cnf->useropts);
                  ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
               }

               /* Run the conference */
               res = conf_run(chan, cnf, confflags.flags, optargs);
            }
            dispose_conf(cnf);
            cnf = NULL;
         }
      }
   } while (allowretry);

   if (cnf)
      dispose_conf(cnf);
   
   return res;
}
static void conf_flush ( int  fd,
struct ast_channel chan 
) [static]

Definition at line 1662 of file app_meetme.c.

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

Referenced by conf_run().

{
   int x;

   /* read any frames that may be waiting on the channel
      and throw them away
   */
   if (chan) {
      struct ast_frame *f;

      /* when no frames are available, this will wait
         for 1 millisecond maximum
      */
      while (ast_waitfor(chan, 1)) {
         f = ast_read(chan);
         if (f)
            ast_frfree(f);
         else /* channel was hung up or something else happened */
            break;
      }
   }

   /* flush any data sitting in the pseudo channel */
   x = DAHDI_FLUSH_ALL;
   if (ioctl(fd, DAHDI_FLUSH, &x))
      ast_log(LOG_WARNING, "Error flushing channel\n");

}
static int conf_free ( struct ast_conference conf) [static]

Definition at line 1693 of file app_meetme.c.

References ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethread_stop, ast_conference::announcethreadlock, ao2_ref, ast_cond_signal(), ast_filedelete(), AST_FRAME_BITS, ast_free, ast_frfree, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_translator_free_path(), ast_conference::chan, ast_conference::confno, EVENT_FLAG_CALL, ast_conference::fd, ast_conference::lchan, ast_conference::listenlock, manager_event, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, announce_listitem::namerecloc, ast_conference::origframe, ast_conference::playlock, ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthreadlock, ast_conference::transframe, ast_conference::transpath, and ast_conference::usercontainer.

Referenced by dispose_conf().

{
   int x;
   struct announce_listitem *item;
   
   AST_LIST_REMOVE(&confs, conf, list);
   manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);

   if (conf->recording == MEETME_RECORD_ACTIVE) {
      conf->recording = MEETME_RECORD_TERMINATE;
      AST_LIST_UNLOCK(&confs);
      while (1) {
         usleep(1);
         AST_LIST_LOCK(&confs);
         if (conf->recording == MEETME_RECORD_OFF)
            break;
         AST_LIST_UNLOCK(&confs);
      }
   }

   for (x = 0; x < AST_FRAME_BITS; x++) {
      if (conf->transframe[x])
         ast_frfree(conf->transframe[x]);
      if (conf->transpath[x])
         ast_translator_free_path(conf->transpath[x]);
   }
   if (conf->announcethread != AST_PTHREADT_NULL) {
      ast_mutex_lock(&conf->announcelistlock);
      conf->announcethread_stop = 1;
      ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
      ast_cond_signal(&conf->announcelist_addition);
      ast_mutex_unlock(&conf->announcelistlock);
      pthread_join(conf->announcethread, NULL);
   
      while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
         ast_filedelete(item->namerecloc, NULL);
         ao2_ref(item, -1);
      }
      ast_mutex_destroy(&conf->announcelistlock);
   }
   if (conf->origframe)
      ast_frfree(conf->origframe);
   if (conf->lchan)
      ast_hangup(conf->lchan);
   if (conf->chan)
      ast_hangup(conf->chan);
   if (conf->fd >= 0)
      close(conf->fd);
   if (conf->recordingfilename) {
      ast_free(conf->recordingfilename);
   }
   if (conf->recordingformat) {
      ast_free(conf->recordingformat);
   }
   if (conf->usercontainer) {
      ao2_ref(conf->usercontainer, -1);
   }
   ast_mutex_destroy(&conf->playlock);
   ast_mutex_destroy(&conf->listenlock);
   ast_mutex_destroy(&conf->recordthreadlock);
   ast_mutex_destroy(&conf->announcethreadlock);
   ast_free(conf);

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

Definition at line 1013 of file app_meetme.c.

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

Referenced by conf_run().

{
   unsigned char *data;
   int len;
   int res = -1;

   if (!ast_check_hangup(chan))
      res = ast_autoservice_start(chan);

   AST_LIST_LOCK(&confs);

   switch(sound) {
   case ENTER:
      data = enter;
      len = sizeof(enter);
      break;
   case LEAVE:
      data = leave;
      len = sizeof(leave);
      break;
   default:
      data = NULL;
      len = 0;
   }
   if (data) {
      careful_write(conf->fd, data, len, 1);
   }

   AST_LIST_UNLOCK(&confs);

   if (!res) 
      ast_autoservice_stop(chan);
}
static void conf_queue_dtmf ( const struct ast_conference conf,
const struct ast_conf_user sender,
struct ast_frame f 
) [static]

Definition at line 1759 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, ast_channel::name, user, and ast_conference::usercontainer.

Referenced by conf_run().

{
   struct ast_conf_user *user;
   struct ao2_iterator user_iter;

   user_iter = ao2_iterator_init(conf->usercontainer, 0);
   while ((user = ao2_iterator_next(&user_iter))) {
      if (user == sender) {
         ao2_ref(user, -1);
         continue;
      }
      if (ast_write(user->chan, f) < 0)
         ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
      ao2_ref(user, -1);
   }
   ao2_iterator_destroy(&user_iter);
}
static int conf_run ( struct ast_channel chan,
struct ast_conference conf,
int  confflags,
char *  optargs[] 
) [static]

Definition at line 2052 of file app_meetme.c.

References volume::actual, ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, announce_thread(), ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethreadlock, announce_listitem::announcetype, ao2_alloc, ao2_callback, ao2_find, 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_changed(), AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_silence(), ast_exists_extension(), ast_filedelete(), AST_FORMAT_SLINEAR, ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_frfree, AST_FRIENDLY_OFFSET, 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_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), ast_mktime(), ast_moh_start(), ast_moh_stop(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_read(), ast_read_noaudio(), ast_realtime_require_field(), ast_record_review(), ast_request(), ast_safe_sleep(), ast_samp2tv(), ast_say_digits(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_translate(), ast_translator_build_path(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_update_realtime(), ast_variables_destroy(), ast_verb, ast_verbose(), ast_waitfor_nandfds(), ast_waitstream(), ast_write(), audio_buffers, ast_channel::audiohooks, ast_conference::bookid, buf, can_write(), careful_write(), ast_conference::chan, chan, ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, conf_flush(), CONF_HASJOIN, CONF_HASLEFT, conf_play(), conf_queue_dtmf(), CONF_SIZE, conf_start_moh(), announce_listitem::confchan, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_DURATION_LIMIT, CONFFLAG_DURATION_STOP, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_KEYEXIT, CONFFLAG_KICK_CONTINUE, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_SLA_STATION, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, announce_listitem::confusers, ast_channel::context, ast_conf_user::dahdichannel, ast_conference::dahdiconf, ast_frame::data, ast_frame::datalen, DATE_FORMAT, volume::desired, dtmfstr, ast_conf_user::end_sound, ast_conference::endalert, ast_conference::endtime, ENTER, errno, EVENT_FLAG_CALL, exitcontext, f, ast_channel::fds, ast_frame::frametype, ast_conf_user::jointime, ast_conf_user::kicktime, announce_listitem::language, ast_channel::language, ast_conference::lchan, LEAVE, ast_conf_user::listen, ast_conference::listenlock, ast_conference::locked, LOG_WARNING, ast_channel::macrocontext, manager_event, ast_conference::markedusers, ast_conference::maxusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, ast_channel::monitor, ast_variable::name, ast_channel::name, announce_listitem::namerecloc, ast_conf_user::namerecloc, ast_variable::next, OBJ_NODATA, ast_frame::offset, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_EXITKEYS, OPT_ARG_MOH_CLASS, OPT_ARG_WAITMARKED, ast_conference::origframe, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_conf_user::play_warning, ast_conference::playlock, ast_frame::ptr, ast_channel::rawwriteformat, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, reset_volumes(), RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, rt_extend_conf(), S_OR, ast_frame::samples, sec, set_talk_volume(), set_user_talking(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_conf_user::start_time, strsep(), ast_frame::subclass, ast_conf_user::talk, ast_conf_user::talking, ast_channel::tech, THRESHOLD_SILENCE, ast_conf_user::timelimit, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_conference::uniqueid, ast_channel::uniqueid, user_max_cmp(), ast_conf_user::user_no, ast_conference::usercontainer, ast_conf_user::userflags, ast_conference::users, ast_variable::value, var, VOL_DOWN, VOL_UP, ast_conf_user::warning_freq, and ast_conf_user::warning_sound.

Referenced by conf_exec(), dial_trunk(), run_station(), sla_station_exec(), and sla_trunk_exec().

{
   struct ast_conf_user *user = NULL;
   int fd;
   struct dahdi_confinfo dahdic, dahdic_empty;
   struct ast_frame *f;
   struct ast_channel *c;
   struct ast_frame fr;
   int outfd;
   int ms;
   int nfds;
   int res;
   int retrydahdi;
   int origfd;
   int musiconhold = 0, mohtempstopped = 0;
   int firstpass = 0;
   int lastmarked = 0;
   int currentmarked = 0;
   int ret = -1;
   int x;
   int menu_active = 0;
   int talkreq_manager = 0;
   int using_pseudo = 0;
   int duration = 20;
   int hr, min, sec;
   int sent_event = 0;
   int checked = 0;
   int announcement_played = 0;
   struct timeval now;
   struct ast_dsp *dsp = NULL;
   struct ast_app *agi_app;
   char *agifile;
   const char *agifiledefault = "conf-background.agi", *tmpvar;
   char meetmesecs[30] = "";
   char exitcontext[AST_MAX_CONTEXT] = "";
   char recordingtmp[AST_MAX_EXTENSION] = "";
   char members[10] = "";
   int dtmf, opt_waitmarked_timeout = 0;
   time_t timeout = 0;
   struct dahdi_bufferinfo bi;
   char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
   char *buf = __buf + AST_FRIENDLY_OFFSET;
   char *exitkeys = NULL;
   unsigned int calldurationlimit = 0;
   long timelimit = 0;
   long play_warning = 0;
   long warning_freq = 0;
   const char *warning_sound = NULL;
   const char *end_sound = NULL;
   char *parse;   
   long time_left_ms = 0;
   struct timeval nexteventts = { 0, };
   int to;
   int setusercount = 0;
   int confsilence = 0, totalsilence = 0;

   if (!(user = ao2_alloc(sizeof(*user), NULL))) {
      return ret;
   }

   /* Possible timeout waiting for marked user */
   if ((confflags & CONFFLAG_WAITMARKED) &&
      !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
      (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
      (opt_waitmarked_timeout > 0)) {
      timeout = time(NULL) + opt_waitmarked_timeout;
   }
      
   if ((confflags & CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
      calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
      ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
   }
   
   if ((confflags & CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
      char *limit_str, *warning_str, *warnfreq_str;
      const char *var;
 
      parse = optargs[OPT_ARG_DURATION_LIMIT];
      limit_str = strsep(&parse, ":");
      warning_str = strsep(&parse, ":");
      warnfreq_str = parse;
 
      timelimit = atol(limit_str);
      if (warning_str)
         play_warning = atol(warning_str);
      if (warnfreq_str)
         warning_freq = atol(warnfreq_str);
 
      if (!timelimit) {
         timelimit = play_warning = warning_freq = 0;
         warning_sound = NULL;
      } else if (play_warning > timelimit) {       
         if (!warning_freq) {
            play_warning = 0;
         } else {
            while (play_warning > timelimit)
               play_warning -= warning_freq;
            if (play_warning < 1)
               play_warning = warning_freq = 0;
         }
      }
      
      ast_channel_lock(chan);
      if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
         var = ast_strdupa(var);
      }
      ast_channel_unlock(chan);

      warning_sound = var ? var : "timeleft";
      
      ast_channel_lock(chan);
      if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
         var = ast_strdupa(var);
      }
      ast_channel_unlock(chan);
      
      end_sound = var ? var : NULL;
         
      /* undo effect of S(x) in case they are both used */
      calldurationlimit = 0;
      /* more efficient do it like S(x) does since no advanced opts */
      if (!play_warning && !end_sound && timelimit) { 
         calldurationlimit = timelimit / 1000;
         timelimit = play_warning = warning_freq = 0;
      } else {
         ast_debug(2, "Limit Data for this call:\n");
         ast_debug(2, "- timelimit     = %ld\n", timelimit);
         ast_debug(2, "- play_warning  = %ld\n", play_warning);
         ast_debug(2, "- warning_freq  = %ld\n", warning_freq);
         ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
         ast_debug(2, "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
      }
   }

   /* Get exit keys */
   if ((confflags & CONFFLAG_KEYEXIT)) {
      if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
         exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
      else
         exitkeys = ast_strdupa("#"); /* Default */
   }
   
   if (confflags & CONFFLAG_RECORDCONF) {
      if (!conf->recordingfilename) {
         const char *var;
         ast_channel_lock(chan);
         if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
            conf->recordingfilename = ast_strdup(var);
         }
         if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
            conf->recordingformat = ast_strdup(var);
         }
         ast_channel_unlock(chan);
         if (!conf->recordingfilename) {
            snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
            conf->recordingfilename = ast_strdup(recordingtmp);
         }
         if (!conf->recordingformat) {
            conf->recordingformat = ast_strdup("wav");
         }
         ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
                conf->confno, conf->recordingfilename, conf->recordingformat);
      }
   }

   ast_mutex_lock(&conf->recordthreadlock);
   if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
      ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
      ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
      dahdic.chan = 0;
      dahdic.confno = conf->dahdiconf;
      dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
      if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
         ast_log(LOG_WARNING, "Error starting listen channel\n");
         ast_hangup(conf->lchan);
         conf->lchan = NULL;
      } else {
         ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
      }
   }
   ast_mutex_unlock(&conf->recordthreadlock);

   ast_mutex_lock(&conf->announcethreadlock);
   if ((conf->announcethread == AST_PTHREADT_NULL) && !(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
      ast_mutex_init(&conf->announcelistlock);
      AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
      ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
   }
   ast_mutex_unlock(&conf->announcethreadlock);

   time(&user->jointime);
   
   user->timelimit = timelimit;
   user->play_warning = play_warning;
   user->warning_freq = warning_freq;
   user->warning_sound = warning_sound;
   user->end_sound = end_sound;  
   
   if (calldurationlimit > 0) {
      time(&user->kicktime);
      user->kicktime = user->kicktime + calldurationlimit;
   }
   
   if (ast_tvzero(user->start_time))
      user->start_time = ast_tvnow();
   time_left_ms = user->timelimit;
   
   if (user->timelimit) {
      nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
      nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
   }

   if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
      /* Sorry, but this conference is locked! */  
      if (!ast_streamfile(chan, "conf-locked", chan->language))
         ast_waitstream(chan, "");
      goto outrun;
   }

      ast_mutex_lock(&conf->playlock);

   if (rt_schedule && conf->maxusers) {
      if (conf->users >= conf->maxusers) {
         /* Sorry, but this confernce has reached the participant limit! */   
         if (!ast_streamfile(chan, "conf-full", chan->language))
            ast_waitstream(chan, "");
         ast_mutex_unlock(&conf->playlock);
         goto outrun;
      }
   }

   ao2_lock(conf->usercontainer);
   ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &user->user_no);
   user->user_no++;
   ao2_link(conf->usercontainer, user);
   ao2_unlock(conf->usercontainer);

   user->chan = chan;
   user->userflags = confflags;
   user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
   user->talking = -1;

   ast_mutex_unlock(&conf->playlock);

   if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
      char destdir[PATH_MAX];

      snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);

      if (ast_mkdir(destdir, 0777) != 0) {
         ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
         goto outrun;
      }

      snprintf(user->namerecloc, sizeof(user->namerecloc),
          "%s/meetme-username-%s-%d", destdir,
          conf->confno, user->user_no);
      if (confflags & CONFFLAG_INTROUSERNOREVIEW)
         res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
      else
         res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
      if (res == -1)
         goto outrun;
   }

   ast_mutex_lock(&conf->playlock);

   if (confflags & CONFFLAG_MARKEDUSER)
      conf->markedusers++;
   conf->users++;
   if (rt_log_members) {
      /* Update table */
      snprintf(members, sizeof(members), "%d", conf->users);
      ast_realtime_require_field("meetme",
         "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
         "members", RQ_UINTEGER1, strlen(members),
         NULL);
      ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
   }
   setusercount = 1;

   /* This device changed state now - if this is the first user */
   if (conf->users == 1)
      ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);

   ast_mutex_unlock(&conf->playlock);

   /* return the unique ID of the conference */
   pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);

   if (confflags & CONFFLAG_EXIT_CONTEXT) {
      ast_channel_lock(chan);
      if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
         ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
      } else if (!ast_strlen_zero(chan->macrocontext)) {
         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
      } else {
         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
      }
      ast_channel_unlock(chan);
   }

   if (!(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
      if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
         if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
            ast_waitstream(chan, "");
      if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
         if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
            ast_waitstream(chan, "");
   }

   if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
      int keepplaying = 1;

      if (conf->users == 2) { 
         if (!ast_streamfile(chan, "conf-onlyone", chan->language)) {
            res = ast_waitstream(chan, AST_DIGIT_ANY);
            ast_stopstream(chan);
            if (res > 0)
               keepplaying = 0;
            else if (res == -1)
               goto outrun;
         }
      } else { 
         if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
            res = ast_waitstream(chan, AST_DIGIT_ANY);
            ast_stopstream(chan);
            if (res > 0)
               keepplaying = 0;
            else if (res == -1)
               goto outrun;
         }
         if (keepplaying) {
            res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
            if (res > 0)
               keepplaying = 0;
            else if (res == -1)
               goto outrun;
         }
         if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
            res = ast_waitstream(chan, AST_DIGIT_ANY);
            ast_stopstream(chan);
            if (res > 0)
               keepplaying = 0;
            else if (res == -1) 
               goto outrun;
         }
      }
   }

   if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
      /* We're leaving this alone until the state gets changed to up */
      ast_indicate(chan, -1);
   }

   if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
      ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
      goto outrun;
   }

   if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
      ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
      goto outrun;
   }

   retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
   user->dahdichannel = !retrydahdi;

 dahdiretry:
   origfd = chan->fds[0];
   if (retrydahdi) {
      /* open pseudo in non-blocking mode */
      fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
      if (fd < 0) {
         ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
         goto outrun;
      }
      using_pseudo = 1;
      /* Setup buffering information */
      memset(&bi, 0, sizeof(bi));
      bi.bufsize = CONF_SIZE / 2;
      bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
      bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
      bi.numbufs = audio_buffers;
      if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
         ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
         close(fd);
         goto outrun;
      }
      x = 1;
      if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
         ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
         close(fd);
         goto outrun;
      }
      nfds = 1;
   } else {
      /* XXX Make sure we're not running on a pseudo channel XXX */
      fd = chan->fds[0];
      nfds = 0;
   }
   memset(&dahdic, 0, sizeof(dahdic));
   memset(&dahdic_empty, 0, sizeof(dahdic_empty));
   /* Check to see if we're in a conference... */
   dahdic.chan = 0;  
   if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
      ast_log(LOG_WARNING, "Error getting conference\n");
      close(fd);
      goto outrun;
   }
   if (dahdic.confmode) {
      /* Whoa, already in a conference...  Retry... */
      if (!retrydahdi) {
         ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
         retrydahdi = 1;
         goto dahdiretry;
      }
   }
   memset(&dahdic, 0, sizeof(dahdic));
   /* Add us to the conference */
   dahdic.chan = 0;  
   dahdic.confno = conf->dahdiconf;

   if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
      struct announce_listitem *item;
      if (!(item = ao2_alloc(sizeof(*item), NULL)))
         goto outrun;
      ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
      ast_copy_string(item->language, chan->language, sizeof(item->language));
      item->confchan = conf->chan;
      item->confusers = conf->users;
      item->announcetype = CONF_HASJOIN;
      ast_mutex_lock(&conf->announcelistlock);
      ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
      AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
      ast_cond_signal(&conf->announcelist_addition);
      ast_mutex_unlock(&conf->announcelistlock);

      while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
         ;
      }
      ao2_ref(item, -1);
   }

   if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers)
      dahdic.confmode = DAHDI_CONF_CONF;
   else if (confflags & CONFFLAG_MONITOR)
      dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
   else if (confflags & CONFFLAG_TALKER)
      dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
   else 
      dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;

   if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
      ast_log(LOG_WARNING, "Error setting conference\n");
      close(fd);
      goto outrun;
   }
   ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf);

   if (!sent_event) {
      manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
                 "Channel: %s\r\n"
                 "Uniqueid: %s\r\n"
            "Meetme: %s\r\n"
            "Usernum: %d\r\n"
            "CallerIDnum: %s\r\n"
                  "CallerIDname: %s\r\n",
                  chan->name, chan->uniqueid, conf->confno, 
            user->user_no,
            S_OR(user->chan->cid.cid_num, "<unknown>"),
            S_OR(user->chan->cid.cid_name, "<unknown>")
            );
      sent_event = 1;
   }

   if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
      firstpass = 1;
      if (!(confflags & CONFFLAG_QUIET))
         if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
            conf_play(chan, conf, ENTER);
   }

   conf_flush(fd, chan);

   if (dsp)
      ast_dsp_free(dsp);

   if (!(dsp = ast_dsp_new())) {
      ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
      res = -1;
   }

   if (confflags & CONFFLAG_AGI) {
      /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
         or use default filename of conf-background.agi */

      ast_channel_lock(chan);
      if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
         agifile = ast_strdupa(tmpvar);
      } else {
         agifile = ast_strdupa(agifiledefault);
      }
      ast_channel_unlock(chan);
      
      if (user->dahdichannel) {
         /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
         x = 1;
         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
      }
      /* Find a pointer to the agi app and execute the script */
      agi_app = pbx_findapp("agi");
      if (agi_app) {
         ret = pbx_exec(chan, agi_app, agifile);
      } else {
         ast_log(LOG_WARNING, "Could not find application (agi)\n");
         ret = -2;
      }
      if (user->dahdichannel) {
         /*  Remove CONFMUTE mode on DAHDI channel */
         x = 0;
         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
      }
   } else {
      if (user->dahdichannel && (confflags & CONFFLAG_STARMENU)) {
         /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
         x = 1;
         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
      }  
      for (;;) {
         int menu_was_active = 0;

         outfd = -1;
         ms = -1;
         now = ast_tvnow();

         if (rt_schedule && conf->endtime) {
            char currenttime[32];
            long localendtime = 0;
            int extended = 0;
            struct ast_tm tm;
            struct ast_variable *var, *origvar;
            struct timeval tmp;

            if (now.tv_sec % 60 == 0) {
               if (!checked) {
                  ast_localtime(&now, &tm, NULL);
                  ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
                  var = origvar = ast_load_realtime("meetme", "confno",
                     conf->confno, "starttime <=", currenttime,
                      "endtime >=", currenttime, NULL);

                  for ( ; var; var = var->next) {
                     if (!strcasecmp(var->name, "endtime")) {
                        struct ast_tm endtime_tm;
                        ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
                        tmp = ast_mktime(&endtime_tm, NULL);
                        localendtime = tmp.tv_sec;
                     }
                  }
                  ast_variables_destroy(origvar);

                  /* A conference can be extended from the
                     Admin/User menu or by an external source */
                  if (localendtime > conf->endtime){
                     conf->endtime = localendtime;
                     extended = 1;
                  }

                  if (conf->endtime && (now.tv_sec >= conf->endtime)) {
                     ast_verbose("Quitting time...\n");
                     goto outrun;
                  }

                  if (!announcement_played && conf->endalert) {
                     if (now.tv_sec + conf->endalert >= conf->endtime) {
                        if (!ast_streamfile(chan, "conf-will-end-in", chan->language))
                           ast_waitstream(chan, "");
                        ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language);
                        if (!ast_streamfile(chan, "minutes", chan->language))
                           ast_waitstream(chan, "");
                        if (musiconhold) {
                           conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
                        }
                        announcement_played = 1;
                     }
                  }

                  if (extended) {
                     announcement_played = 0;
                  }

                  checked = 1;
               }
            } else {
               checked = 0;
            }
         }

         if (user->kicktime && (user->kicktime <= now.tv_sec)) {
            if (confflags & CONFFLAG_KICK_CONTINUE) {
               ret = 0;
            } else {
               ret = -1;
            }
            break;
         }
  
         to = -1;
         if (user->timelimit) {
            int minutes = 0, seconds = 0, remain = 0;
 
            to = ast_tvdiff_ms(nexteventts, now);
            if (to < 0) {
               to = 0;
            }
            time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
            if (time_left_ms < to) {
               to = time_left_ms;
            }
   
            if (time_left_ms <= 0) {
               if (user->end_sound) {                 
                  res = ast_streamfile(chan, user->end_sound, chan->language);
                  res = ast_waitstream(chan, "");
               }
               break;
            }
            
            if (!to) {
               if (time_left_ms >= 5000) {                  
                  
                  remain = (time_left_ms + 500) / 1000;
                  if (remain / 60 >= 1) {
                     minutes = remain / 60;
                     seconds = remain % 60;
                  } else {
                     seconds = remain;
                  }
                  
                  /* force the time left to round up if appropriate */
                  if (user->warning_sound && user->play_warning) {
                     if (!strcmp(user->warning_sound, "timeleft")) {
                        
                        res = ast_streamfile(chan, "vm-youhave", chan->language);
                        res = ast_waitstream(chan, "");
                        if (minutes) {
                           res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL);
                           res = ast_streamfile(chan, "queue-minutes", chan->language);
                           res = ast_waitstream(chan, "");
                        }
                        if (seconds) {
                           res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL);
                           res = ast_streamfile(chan, "queue-seconds", chan->language);
                           res = ast_waitstream(chan, "");
                        }
                     } else {
                        res = ast_streamfile(chan, user->warning_sound, chan->language);
                        res = ast_waitstream(chan, "");
                     }
                     if (musiconhold) {
                        conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
                     }
                  }
               }
               if (user->warning_freq) {
                  nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
               } else {
                  nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
               }
            }
         }

         now = ast_tvnow();
         if (timeout && now.tv_sec >= timeout) {
            if (confflags & CONFFLAG_KICK_CONTINUE) {
               ret = 0;
            } else {
               ret = -1;
            }
            break;
         }

         /* if we have just exited from the menu, and the user had a channel-driver
            volume adjustment, restore it
         */
         if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual) {
            set_talk_volume(user, user->listen.desired);
         }

         menu_was_active = menu_active;

         currentmarked = conf->markedusers;
         if (!(confflags & CONFFLAG_QUIET) &&
             (confflags & CONFFLAG_MARKEDUSER) &&
             (confflags & CONFFLAG_WAITMARKED) &&
             lastmarked == 0) {
            if (currentmarked == 1 && conf->users > 1) {
               ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
               if (conf->users - 1 == 1) {
                  if (!ast_streamfile(chan, "conf-userwilljoin", chan->language)) {
                     ast_waitstream(chan, "");
                  }
               } else {
                  if (!ast_streamfile(chan, "conf-userswilljoin", chan->language)) {
                     ast_waitstream(chan, "");
                  }
               }
            }
            if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER)) {
               if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) {
                  ast_waitstream(chan, "");
               }
            }
         }

         /* Update the struct with the actual confflags */
         user->userflags = confflags;

         if (confflags & CONFFLAG_WAITMARKED) {
            if (currentmarked == 0) {
               if (lastmarked != 0) {
                  if (!(confflags & CONFFLAG_QUIET)) {
                     if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language)) {
                        ast_waitstream(chan, "");
                     }
                  }
                  if (confflags & CONFFLAG_MARKEDEXIT) {
                     if (confflags & CONFFLAG_KICK_CONTINUE) {
                        ret = 0;
                     }
                     break;
                  } else {
                     dahdic.confmode = DAHDI_CONF_CONF;
                     if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
                        ast_log(LOG_WARNING, "Error setting conference\n");
                        close(fd);
                        goto outrun;
                     }
                  }
               }
               if (!musiconhold && (confflags & CONFFLAG_MOH)) {
                  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
                  musiconhold = 1;
               }
            } else if (currentmarked >= 1 && lastmarked == 0) {
               /* Marked user entered, so cancel timeout */
               timeout = 0;
               if (confflags & CONFFLAG_MONITOR) {
                  dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
               } else if (confflags & CONFFLAG_TALKER) {
                  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
               } else {
                  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
               }
               if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
                  ast_log(LOG_WARNING, "Error setting conference\n");
                  close(fd);
                  goto outrun;
               }
               if (musiconhold && (confflags & CONFFLAG_MOH)) {
                  ast_moh_stop(chan);
                  musiconhold = 0;
               }
               if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
                  if (!ast_streamfile(chan, "conf-placeintoconf", chan->language)) {
                     ast_waitstream(chan, "");
                  }
                  conf_play(chan, conf, ENTER);
               }
            }
         }

         /* trying to add moh for single person conf */
         if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
            if (conf->users == 1) {
               if (!musiconhold) {
                  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
                  musiconhold = 1;
               } 
            } else {
               if (musiconhold) {
                  ast_moh_stop(chan);
                  musiconhold = 0;
               }
            }
         }
         
         /* Leave if the last marked user left */
         if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
            if (confflags & CONFFLAG_KICK_CONTINUE) {
               ret = 0;
            } else {
               ret = -1;
            }
            break;
         }
   
         /* Check if my modes have changed */

         /* If I should be muted but am still talker, mute me */
         if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
            dahdic.confmode ^= DAHDI_CONF_TALKER;
            if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
               ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
               ret = -1;
               break;
            }

            /* Indicate user is not talking anymore - change him to unmonitored state */
            if ((confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) {
               set_user_talking(chan, conf, user, -1, confflags & CONFFLAG_MONITORTALKER);
            }

            manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
                  "Channel: %s\r\n"
                  "Uniqueid: %s\r\n"
                  "Meetme: %s\r\n"
                  "Usernum: %i\r\n"
                  "Status: on\r\n",
                  chan->name, chan->uniqueid, conf->confno, user->user_no);
         }

         /* If I should be un-muted but am not talker, un-mute me */
         if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
            dahdic.confmode |= DAHDI_CONF_TALKER;
            if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
               ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
               ret = -1;
               break;
            }

            manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
                  "Channel: %s\r\n"
                  "Uniqueid: %s\r\n"
                  "Meetme: %s\r\n"
                  "Usernum: %i\r\n"
                  "Status: off\r\n",
                  chan->name, chan->uniqueid, conf->confno, user->user_no);
         }
         
         if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
            (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
            talkreq_manager = 1;

            manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 
                     "Channel: %s\r\n"
                           "Uniqueid: %s\r\n"
                           "Meetme: %s\r\n"
                           "Usernum: %i\r\n"
                           "Status: on\r\n",
                           chan->name, chan->uniqueid, conf->confno, user->user_no);
         }

         
         if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
            !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
            talkreq_manager = 0;
            manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 
                     "Channel: %s\r\n"
                           "Uniqueid: %s\r\n"
                           "Meetme: %s\r\n"
                           "Usernum: %i\r\n"
                           "Status: off\r\n",
                          chan->name, chan->uniqueid, conf->confno, user->user_no);
         }
         
         /* If I have been kicked, exit the conference */
         if (user->adminflags & ADMINFLAG_KICKME) {
            /* You have been kicked. */
            if (!(confflags & CONFFLAG_QUIET) && 
               !ast_streamfile(chan, "conf-kicked", chan->language)) {
               ast_waitstream(chan, "");
            }
            ret = 0;
            break;
         }

         c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);

         if (c) {
            char dtmfstr[2] = "";

            if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) {
               if (using_pseudo) {
                  /* Kill old pseudo */
                  close(fd);
                  using_pseudo = 0;
               }
               ast_debug(1, "Ooh, something swapped out under us, starting over\n");
               retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0);
               user->dahdichannel = !retrydahdi;
               goto dahdiretry;
            }
            if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
               f = ast_read_noaudio(c);
            } else {
               f = ast_read(c);
            }
            if (!f) {
               break;
            }
            if (f->frametype == AST_FRAME_DTMF) {
               dtmfstr[0] = f->subclass;
               dtmfstr[1] = '\0';
            }

            if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
               if (user->talk.actual) {
                  ast_frame_adjust_volume(f, user->talk.actual);
               }

               if (confflags & (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER)) {
                  if (user->talking == -1) {
                     user->talking = 0;
                  }

                  res = ast_dsp_silence(dsp, f, &totalsilence);
                  if (totalsilence < MEETME_DELAYDETECTTALK) {
                     set_user_talking(chan, conf, user, 1, confflags & CONFFLAG_MONITORTALKER);
                  }
                  if (totalsilence > MEETME_DELAYDETECTENDTALK) {
                     set_user_talking(chan, conf, user, 0, confflags & CONFFLAG_MONITORTALKER);
                  }
               }
               if (using_pseudo) {
                  /* Absolutely do _not_ use careful_write here...
                     it is important that we read data from the channel
                     as fast as it arrives, and feed it into the conference.
                     The buffering in the pseudo channel will take care of any
                     timing differences, unless they are so drastic as to lose
                     audio frames (in which case carefully writing would only
                     have delayed the audio even further).
                  */
                  /* As it turns out, we do want to use careful write.  We just
                     don't want to block, but we do want to at least *try*
                     to write out all the samples.
                   */
                  if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER)) {
                     careful_write(fd, f->data.ptr, f->datalen, 0);
                  }
               }
            } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
               if (confflags & CONFFLAG_PASS_DTMF) {
                  conf_queue_dtmf(conf, user, f);
               }
               if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
                  ast_log(LOG_WARNING, "Error setting conference\n");
                  close(fd);
                  ast_frfree(f);
                  goto outrun;
               }

               /* if we are entering the menu, and the user has a channel-driver
                  volume adjustment, clear it
               */
               if (!menu_active && user->talk.desired && !user->talk.actual) {
                  set_talk_volume(user, 0);
               }

               if (musiconhold) {
                     ast_moh_stop(chan);
               }
               if ((confflags & CONFFLAG_ADMIN)) {
                  /* Admin menu */
                  if (!menu_active) {
                     menu_active = 1;
                     /* Record this sound! */
                     if (!ast_streamfile(chan, "conf-adminmenu-162", chan->language)) {
                        dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
                        ast_stopstream(chan);
                     } else {
                        dtmf = 0;
                     }
                  } else {
                     dtmf = f->subclass;
                  }
                  if (dtmf) {
                     switch(dtmf) {
                     case '1': /* Un/Mute */
                        menu_active = 0;

                        /* for admin, change both admin and use flags */
                        if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
                           user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
                        } else {
                           user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
                        }

                        if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
                           if (!ast_streamfile(chan, "conf-muted", chan->language)) {
                              ast_waitstream(chan, "");
                           }
                        } else {
                           if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
                              ast_waitstream(chan, "");
                           }
                        }
                        break;
                     case '2': /* Un/Lock the Conference */
                        menu_active = 0;
                        if (conf->locked) {
                           conf->locked = 0;
                           if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) {
                              ast_waitstream(chan, "");
                           }
                        } else {
                           conf->locked = 1;
                           if (!ast_streamfile(chan, "conf-lockednow", chan->language)) {
                              ast_waitstream(chan, "");
                           }
                        }
                        break;
                     case '3': /* Eject last user */
                     {
                        struct ast_conf_user *usr = NULL;
                        int max_no = 0;
                        menu_active = 0;
                        ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
                        usr = ao2_find(conf->usercontainer, &max_no, 0);
                        if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
                           if(!ast_streamfile(chan, "conf-errormenu", chan->language))
                              ast_waitstream(chan, "");
                        } else {
                           usr->adminflags |= ADMINFLAG_KICKME;
                        }
                        ao2_ref(usr, -1);
                        ast_stopstream(chan);
                        break;
                     }
                     case '4':
                        tweak_listen_volume(user, VOL_DOWN);
                        break;
                     case '5':
                        /* Extend RT conference */
                        if (rt_schedule) {
                           if (!rt_extend_conf(conf->confno)) {
                              if (!ast_streamfile(chan, "conf-extended", chan->language)) {
                                 ast_waitstream(chan, "");
                              }
                           } else {
                              if (!ast_streamfile(chan, "conf-nonextended", chan->language)) {
                                 ast_waitstream(chan, "");
                              }
                           }
                           ast_stopstream(chan);
                        }
                        menu_active = 0;
                        break;
                     case '6':
                        tweak_listen_volume(user, VOL_UP);
                        break;
                     case '7':
                        tweak_talk_volume(user, VOL_DOWN);
                        break;
                     case '8':
                        menu_active = 0;
                        break;
                     case '9':
                        tweak_talk_volume(user, VOL_UP);
                        break;
                     default:
                        menu_active = 0;
                        /* Play an error message! */
                        if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
                           ast_waitstream(chan, "");
                        }
                        break;
                     }
                  }
               } else {
                  /* User menu */
                  if (!menu_active) {
                     menu_active = 1;
                     if (!ast_streamfile(chan, "conf-usermenu-162", chan->language)) {
                        dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
                        ast_stopstream(chan);
                     } else {
                        dtmf = 0;
                     }
                  } else {
                     dtmf = f->subclass;
                  }
                  if (dtmf) {
                     switch (dtmf) {
                     case '1': /* Un/Mute */
                        menu_active = 0;

                        /* user can only toggle the self-muted state */
                        user->adminflags ^= ADMINFLAG_SELFMUTED;

                        /* they can't override the admin mute state */
                        if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
                           if (!ast_streamfile(chan, "conf-muted", chan->language)) {
                              ast_waitstream(chan, "");
                           }
                        } else {
                           if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
                              ast_waitstream(chan, "");
                           }
                        }
                        break;
                     case '2':
                        menu_active = 0;
                        if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
                           user->adminflags |= ADMINFLAG_T_REQUEST;
                        }
                           
                        if (user->adminflags & ADMINFLAG_T_REQUEST) {
                           if (!ast_streamfile(chan, "beep", chan->language)) {
                              ast_waitstream(chan, "");
                           }
                        }
                        break;
                     case '4':
                        tweak_listen_volume(user, VOL_DOWN);
                        break;
                     case '5':
                        /* Extend RT conference */
                        if (rt_schedule) {
                           rt_extend_conf(conf->confno);
                        }
                        menu_active = 0;
                        break;
                     case '6':
                        tweak_listen_volume(user, VOL_UP);
                        break;
                     case '7':
                        tweak_talk_volume(user, VOL_DOWN);
                        break;
                     case '8':
                        menu_active = 0;
                        break;
                     case '9':
                        tweak_talk_volume(user, VOL_UP);
                        break;
                     default:
                        menu_active = 0;
                        if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
                           ast_waitstream(chan, "");
                        }
                        break;
                     }
                  }
               }
               if (musiconhold) {
                  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
               }

               if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
                  ast_log(LOG_WARNING, "Error setting conference\n");
                  close(fd);
                  ast_frfree(f);
                  goto outrun;
               }

               conf_flush(fd, chan);
            /* Since this option could absorb DTMF meant for the previous (menu), we have to check this one last */
            } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
               if (confflags & CONFFLAG_PASS_DTMF) {
                  conf_queue_dtmf(conf, user, f);
               }

               if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
                  ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
                  ret = 0;
                  ast_frfree(f);
                  break;
               } else {
                  ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
               }
            } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) {
               pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
                  
               if (confflags & CONFFLAG_PASS_DTMF) {
                  conf_queue_dtmf(conf, user, f);
               }
               ret = 0;
               ast_frfree(f);
               break;
            } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
               && confflags & CONFFLAG_PASS_DTMF) {
               conf_queue_dtmf(conf, user, f);
            } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
               switch (f->subclass) {
               case AST_CONTROL_HOLD:
                  sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
                  break;
               default:
                  break;
               }
            } else if (f->frametype == AST_FRAME_NULL) {
               /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
            } else if (f->frametype == AST_FRAME_CONTROL) {
               switch (f->subclass) {
               case AST_CONTROL_BUSY:
               case AST_CONTROL_CONGESTION:
                  ast_frfree(f);
                  goto outrun;
                  break;
               default:
                  ast_debug(1, 
                     "Got ignored control frame on channel %s, f->frametype=%d,f->subclass=%d\n",
                     chan->name, f->frametype, f->subclass);
               }
            } else {
               ast_debug(1, 
                  "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
                  chan->name, f->frametype, f->subclass);
            }
            ast_frfree(f);
         } else if (outfd > -1) {
            res = read(outfd, buf, CONF_SIZE);
            if (res > 0) {
               memset(&fr, 0, sizeof(fr));
               fr.frametype = AST_FRAME_VOICE;
               fr.subclass = AST_FORMAT_SLINEAR;
               fr.datalen = res;
               fr.samples = res / 2;
               fr.data.ptr = buf;
               fr.offset = AST_FRIENDLY_OFFSET;
               if (!user->listen.actual &&
                  ((confflags & CONFFLAG_MONITOR) ||
                   (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
                   (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
                   )) {
                  int idx;
                  for (idx = 0; idx < AST_FRAME_BITS; idx++) {
                     if (chan->rawwriteformat & (1 << idx)) {
                        break;
                     }
                  }
                  if (idx >= AST_FRAME_BITS) {
                     goto bailoutandtrynormal;
                  }
                  ast_mutex_lock(&conf->listenlock);
                  if (!conf->transframe[idx]) {
                     if (conf->origframe) {
                        if (musiconhold && !ast_dsp_silence(dsp, conf->origframe, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
                           ast_moh_stop(chan);
                           mohtempstopped = 1;
                        }
                        if (!conf->transpath[idx]) {
                           conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR);
                        }
                        if (conf->transpath[idx]) {
                           conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
                           if (!conf->transframe[idx]) {
                              conf->transframe[idx] = &ast_null_frame;
                           }
                        }
                     }
                  }
                  if (conf->transframe[idx]) {
                     if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
                         can_write(chan, confflags)) {
                        struct ast_frame *cur;
                        /* the translator may have returned a list of frames, so
                           write each one onto the channel
                        */
                        for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
                           if (ast_write(chan, cur)) {
                              ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
                              break;
                           }
                        }
                        if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
                           mohtempstopped = 0;
                           ast_moh_start(chan, NULL, NULL);
                        }
                     }
                  } else {
                     ast_mutex_unlock(&conf->listenlock);
                     goto bailoutandtrynormal;
                  }
                  ast_mutex_unlock(&conf->listenlock);
               } else {
bailoutandtrynormal:
                  if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
                     ast_moh_stop(chan);
                     mohtempstopped = 1;
                  }
                  if (user->listen.actual) {
                     ast_frame_adjust_volume(&fr, user->listen.actual);
                  }
                  if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
                     ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
                  }
                  if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
                     mohtempstopped = 0;
                     ast_moh_start(chan, NULL, NULL);
                  }
               }
            } else {
               ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
            }
         }
         lastmarked = currentmarked;
      }
   }

   if (musiconhold) {
      ast_moh_stop(chan);
   }
   
   if (using_pseudo) {
      close(fd);
   } else {
      /* Take out of conference */
      dahdic.chan = 0;  
      dahdic.confno = 0;
      dahdic.confmode = 0;
      if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
         ast_log(LOG_WARNING, "Error setting conference\n");
      }
   }

   reset_volumes(user);

   if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
      conf_play(chan, conf, LEAVE);
   }

   if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
      struct announce_listitem *item;
      if (!(item = ao2_alloc(sizeof(*item), NULL)))
         goto outrun;
      ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
      ast_copy_string(item->language, chan->language, sizeof(item->language));
      item->confchan = conf->chan;
      item->confusers = conf->users;
      item->announcetype = CONF_HASLEFT;
      ast_mutex_lock(&conf->announcelistlock);
      AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
      ast_cond_signal(&conf->announcelist_addition);
      ast_mutex_unlock(&conf->announcelistlock);
   } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) {
      /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
      ast_filedelete(user->namerecloc, NULL);
   }

 outrun:
   AST_LIST_LOCK(&confs);

   if (dsp) {
      ast_dsp_free(dsp);
   }
   
   if (user->user_no) {
      /* Only cleanup users who really joined! */
      now = ast_tvnow();
      hr = (now.tv_sec - user->jointime) / 3600;
      min = ((now.tv_sec - user->jointime) % 3600) / 60;
      sec = (now.tv_sec - user->jointime) % 60;

      if (sent_event) {
         manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
                  "Channel: %s\r\n"
                  "Uniqueid: %s\r\n"
                  "Meetme: %s\r\n"
                  "Usernum: %d\r\n"
                  "CallerIDNum: %s\r\n"
                  "CallerIDName: %s\r\n"
                  "Duration: %ld\r\n",
                  chan->name, chan->uniqueid, conf->confno, 
                  user->user_no,
                  S_OR(user->chan->cid.cid_num, "<unknown>"),
                  S_OR(user->chan->cid.cid_name, "<unknown>"),
                  (long)(now.tv_sec - user->jointime));
      }

      if (setusercount) {
         conf->users--;
         if (rt_log_members) {
            /* Update table */
            snprintf(members, sizeof(members), "%d", conf->users);
            ast_realtime_require_field("meetme",
               "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
               "members", RQ_UINTEGER1, strlen(members),
               NULL);
            ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
         }
         if (confflags & CONFFLAG_MARKEDUSER) {
            conf->markedusers--;
         }
      }
      /* Remove ourselves from the container */
      ao2_unlink(conf->usercontainer, user); 

      /* Change any states */
      if (!conf->users) {
         ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
      }

      /* Return the number of seconds the user was in the conf */
      snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
      pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);

      /* Return the RealTime bookid for CDR linking */
      if (rt_schedule) {
         pbx_builtin_setvar_helper(chan, "MEETMEBOOKID", conf->bookid);
      }
   }
   ao2_ref(user, -1);
   AST_LIST_UNLOCK(&confs);

   return ret;
}
static void conf_start_moh ( struct ast_channel chan,
const char *  musicclass 
) [static]

Definition at line 1931 of file app_meetme.c.

References ast_channel_lock, ast_channel_unlock, ast_moh_start(), ast_strdupa, ast_string_field_set, and ast_channel::musicclass.

Referenced by conf_run().

{
   char *original_moh;

   ast_channel_lock(chan);
   original_moh = ast_strdupa(chan->musicclass);
   ast_string_field_set(chan, musicclass, musicclass);
   ast_channel_unlock(chan);

   ast_moh_start(chan, original_moh, NULL);

   ast_channel_lock(chan);
   ast_string_field_set(chan, musicclass, original_moh);
   ast_channel_unlock(chan);
}
static int count_exec ( struct ast_channel chan,
void *  data 
) [static]

The MeetmeCount application.

Definition at line 3749 of file app_meetme.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_say_number(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), dispose_conf(), find_conf(), ast_channel::language, LOG_WARNING, pbx_builtin_setvar_helper(), and ast_conference::users.

Referenced by load_module().

{
   int res = 0;
   struct ast_conference *conf;
   int count;
   char *localdata;
   char val[80] = "0"; 
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(confno);
      AST_APP_ARG(varname);
   );

   if (ast_strlen_zero(data)) {
      ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
      return -1;
   }
   
   if (!(localdata = ast_strdupa(data)))
      return -1;

   AST_STANDARD_APP_ARGS(args, localdata);
   
   conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);

   if (conf) {
      count = conf->users;
      dispose_conf(conf);
      conf = NULL;
   } else
      count = 0;

   if (!ast_strlen_zero(args.varname)) {
      /* have var so load it and exit */
      snprintf(val, sizeof(val), "%d", count);
      pbx_builtin_setvar_helper(chan, args.varname, val);
   } else {
      if (chan->_state != AST_STATE_UP) {
         ast_answer(chan);
      }
      res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
   }

   return res;
}
static struct sla_trunk_ref* create_trunk_ref ( struct sla_trunk trunk) [static, read]

Definition at line 5959 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

{
   struct sla_trunk_ref *trunk_ref;

   if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
      return NULL;

   trunk_ref->trunk = trunk;

   return trunk_ref;
}
static void destroy_station ( struct sla_station station) [static]

Definition at line 6169 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, sla_registrar, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_build_station(), and sla_destroy().

{
   struct sla_trunk_ref *trunk_ref;

   if (!ast_strlen_zero(station->autocontext)) {
      AST_RWLIST_RDLOCK(&sla_trunks);
      AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
         char exten[AST_MAX_EXTENSION];
         char hint[AST_MAX_APP];
         snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
         snprintf(hint, sizeof(hint), "SLA:%s", exten);
         ast_context_remove_extension(station->autocontext, exten, 
            1, sla_registrar);
         ast_context_remove_extension(station->autocontext, hint, 
            PRIORITY_HINT, sla_registrar);
      }
      AST_RWLIST_UNLOCK(&sla_trunks);
   }

   while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
      ast_free(trunk_ref);

   ast_string_field_free_memory(station);
   ast_free(station);
}
static void destroy_trunk ( struct sla_trunk trunk) [static]

Definition at line 6155 of file app_meetme.c.

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

Referenced by sla_build_trunk(), and sla_destroy().

{
   struct sla_station_ref *station_ref;

   if (!ast_strlen_zero(trunk->autocontext))
      ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);

   while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
      ast_free(station_ref);

   ast_string_field_free_memory(trunk);
   ast_free(trunk);
}
static void* dial_trunk ( void *  data) [static]

Definition at line 5671 of file app_meetme.c.

References ALL_TRUNK_REFS, ast_cond_signal(), ast_dial_answered(), ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_run(), ast_dial_state(), ast_free, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), build_conf(), sla_trunk::chan, sla_trunk_ref::chan, ast_channel::cid, ast_callerid::cid_name, cid_name, ast_callerid::cid_num, cid_num, dial_trunk_args::cond, dial_trunk_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_TRUNK, dispose_conf(), ast_flags::flags, MAX_CONFNUM, sla_trunk::on_hold, sla, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, strsep(), sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.

Referenced by sla_station_exec().

{
   struct dial_trunk_args *args = data;
   struct ast_dial *dial;
   char *tech, *tech_data;
   enum ast_dial_result dial_res;
   char conf_name[MAX_CONFNUM];
   struct ast_conference *conf;
   struct ast_flags conf_flags = { 0 };
   struct sla_trunk_ref *trunk_ref = args->trunk_ref;
   const char *cid_name = NULL, *cid_num = NULL;

   if (!(dial = ast_dial_create())) {
      ast_mutex_lock(args->cond_lock);
      ast_cond_signal(args->cond);
      ast_mutex_unlock(args->cond_lock);
      return NULL;
   }

   tech_data = ast_strdupa(trunk_ref->trunk->device);
   tech = strsep(&tech_data, "/");
   if (ast_dial_append(dial, tech, tech_data) == -1) {
      ast_mutex_lock(args->cond_lock);
      ast_cond_signal(args->cond);
      ast_mutex_unlock(args->cond_lock);
      ast_dial_destroy(dial);
      return NULL;
   }

   if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
      cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
      ast_free(trunk_ref->chan->cid.cid_name);
      trunk_ref->chan->cid.cid_name = NULL;
   }
   if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
      cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
      ast_free(trunk_ref->chan->cid.cid_num);
      trunk_ref->chan->cid.cid_num = NULL;
   }

   dial_res = ast_dial_run(dial, trunk_ref->chan, 1);

   if (cid_name)
      trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
   if (cid_num)
      trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);

   if (dial_res != AST_DIAL_RESULT_TRYING) {
      ast_mutex_lock(args->cond_lock);
      ast_cond_signal(args->cond);
      ast_mutex_unlock(args->cond_lock);
      ast_dial_destroy(dial);
      return NULL;
   }

   for (;;) {
      unsigned int done = 0;
      switch ((dial_res = ast_dial_state(dial))) {
      case AST_DIAL_RESULT_ANSWERED:
         trunk_ref->trunk->chan = ast_dial_answered(dial);
      case AST_DIAL_RESULT_HANGUP:
      case AST_DIAL_RESULT_INVALID:
      case AST_DIAL_RESULT_FAILED:
      case AST_DIAL_RESULT_TIMEOUT:
      case AST_DIAL_RESULT_UNANSWERED:
         done = 1;
      case AST_DIAL_RESULT_TRYING:
      case AST_DIAL_RESULT_RINGING:
      case AST_DIAL_RESULT_PROGRESS:
      case AST_DIAL_RESULT_PROCEEDING:
         break;
      }
      if (done)
         break;
   }

   if (!trunk_ref->trunk->chan) {
      ast_mutex_lock(args->cond_lock);
      ast_cond_signal(args->cond);
      ast_mutex_unlock(args->cond_lock);
      ast_dial_join(dial);
      ast_dial_destroy(dial);
      return NULL;
   }

   snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
   ast_set_flag(&conf_flags, 
      CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
      CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
   conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan);

   ast_mutex_lock(args->cond_lock);
   ast_cond_signal(args->cond);
   ast_mutex_unlock(args->cond_lock);

   if (conf) {
      conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
      dispose_conf(conf);
      conf = NULL;
   }

   /* If the trunk is going away, it is definitely now IDLE. */
   sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);

   trunk_ref->trunk->chan = NULL;
   trunk_ref->trunk->on_hold = 0;

   ast_dial_join(dial);
   ast_dial_destroy(dial);

   return NULL;
}
static int dispose_conf ( struct ast_conference conf) [static]

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

{
   int res = 0;
   int confno_int = 0;

   AST_LIST_LOCK(&confs);
   if (ast_atomic_dec_and_test(&conf->refcount)) {
      /* Take the conference room number out of an inuse state */
      if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
         conf_map[confno_int] = 0;
      }
      conf_free(conf);
      res = 1;
   }
   AST_LIST_UNLOCK(&confs);

   return res;
}
static struct ast_conference* find_conf ( struct ast_channel chan,
char *  confno,
int  make,
int  dynamic,
char *  dynamic_pin,
size_t  pin_buf_len,
int  refcount,
struct ast_flags confflags 
) [static, read]

Definition at line 3645 of file app_meetme.c.

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

Referenced by conf_exec(), and count_exec().

{
   struct ast_config *cfg;
   struct ast_variable *var;
   struct ast_flags config_flags = { 0 };
   struct ast_conference *cnf;

   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(confno);
      AST_APP_ARG(pin);
      AST_APP_ARG(pinadmin);
   );

   /* Check first in the conference list */
   ast_debug(1, "The requested confno is '%s'?\n", confno);
   AST_LIST_LOCK(&confs);
   AST_LIST_TRAVERSE(&confs, cnf, list) {
      ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
      if (!strcmp(confno, cnf->confno)) 
         break;
   }
   if (cnf) {
      cnf->refcount += refcount;
   }
   AST_LIST_UNLOCK(&confs);

   if (!cnf) {
      if (dynamic) {
         /* No need to parse meetme.conf */
         ast_debug(1, "Building dynamic conference '%s'\n", confno);
         if (dynamic_pin) {
            if (dynamic_pin[0] == 'q') {
               /* Query the user to enter a PIN */
               if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
                  return NULL;
            }
            cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
         } else {
            cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
         }
      } else {
         /* Check the config */
         cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
         if (!cfg) {
            ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
            return NULL;
         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
            ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
            return NULL;
         }

         for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
            char parse[MAX_SETTINGS];

            if (strcasecmp(var->name, "conf"))
               continue;

            ast_copy_string(parse, var->value, sizeof(parse));

            AST_STANDARD_APP_ARGS(args, parse);
            ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
            if (!strcasecmp(args.confno, confno)) {
               /* Bingo it's a valid conference */
               cnf = build_conf(args.confno,
                     S_OR(args.pin, ""),
                     S_OR(args.pinadmin, ""),
                     make, dynamic, refcount, chan);
               break;
            }
         }
         if (!var) {
            ast_debug(1, "%s isn't a valid conference\n", confno);
         }
         ast_config_destroy(cfg);
      }
   } else if (dynamic_pin) {
      /* Correct for the user selecting 'D' instead of 'd' to have
         someone join into a conference that has already been created
         with a pin. */
      if (dynamic_pin[0] == 'q') {
         dynamic_pin[0] = '\0';
      }
   }

   if (cnf) {
      if (confflags && !cnf->chan &&
          !ast_test_flag(confflags, CONFFLAG_QUIET) &&
          ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
         ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
         ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
      }
      
      if (confflags && !cnf->chan &&
          ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
         ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
      }
   }

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

Definition at line 3461 of file app_meetme.c.

References ast_conference::adminopts, ast_app_parse_options(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_copy_flags, ast_copy_string(), ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), AST_MAX_EXTENSION, ast_mktime(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_test_flag, ast_tvnow(), ast_variables_destroy(), ast_verb, ast_waitstream(), ast_conference::bookid, build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, ast_conference::confno, DATE_FORMAT, earlyalert, endalert, ast_conference::endalert, ast_conference::endtime, ast_flags::flags, fuzzystart, ast_channel::language, ast_conference::list, LOG_WARNING, ast_conference::maxusers, meetme_opts, ast_variable::name, ast_variable::next, OPTIONS_LEN, pbx_builtin_getvar_helper(), ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::refcount, ast_channel::uniqueid, ast_conference::useropts, ast_variable::value, and var.

Referenced by conf_exec().

{
   struct ast_variable *var, *origvar;
   struct ast_conference *cnf;

   *too_early = 0;

   /* Check first in the conference list */
   AST_LIST_LOCK(&confs);
   AST_LIST_TRAVERSE(&confs, cnf, list) {
      if (!strcmp(confno, cnf->confno)) {
         break;
      }
   }
   if (cnf) {
      cnf->refcount += refcount;
   }
   AST_LIST_UNLOCK(&confs);

   if (!cnf) {
      char *pin = NULL, *pinadmin = NULL; /* For temp use */
      int maxusers = 0;
      struct timeval now;
      char recordingfilename[256] = "";
      char recordingformat[11] = "";
      char currenttime[32] = "";
      char eatime[32] = "";
      char bookid[51] = "";
      char recordingtmp[AST_MAX_EXTENSION] = "";
      char useropts[OPTIONS_LEN + 1] = ""; /* Used for RealTime conferences */
      char adminopts[OPTIONS_LEN + 1] = "";
      struct ast_tm tm, etm;
      struct timeval endtime = { .tv_sec = 0 };
      const char *var2;

      if (rt_schedule) {
         now = ast_tvnow();

         ast_localtime(&now, &tm, NULL);
         ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);

         ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);

         var = ast_load_realtime("meetme", "confno",
            confno, "starttime <= ", currenttime, "endtime >= ",
            currenttime, NULL);

         if (!var && fuzzystart) {
            now = ast_tvnow();
            now.tv_sec += fuzzystart;

            ast_localtime(&now, &tm, NULL);
            ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
            var = ast_load_realtime("meetme", "confno",
               confno, "starttime <= ", currenttime, "endtime >= ",
               currenttime, NULL);
         }

         if (!var && earlyalert) {
            now = ast_tvnow();
            now.tv_sec += earlyalert;
            ast_localtime(&now, &etm, NULL);
            ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
            var = ast_load_realtime("meetme", "confno",
               confno, "starttime <= ", eatime, "endtime >= ",
               currenttime, NULL);
            if (var) {
               *too_early = 1;
            }
         }

      } else {
          var = ast_load_realtime("meetme", "confno", confno, NULL);
      }

      if (!var) {
         return NULL;
      }

      if (rt_schedule && *too_early) {
         /* Announce that the caller is early and exit */
         if (!ast_streamfile(chan, "conf-has-not-started", chan->language)) {
            ast_waitstream(chan, "");
         }
         ast_variables_destroy(var);
         return NULL;
      }

      for (origvar = var; var; var = var->next) {
         if (!strcasecmp(var->name, "pin")) {
            pin = ast_strdupa(var->value);
         } else if (!strcasecmp(var->name, "adminpin")) {
            pinadmin = ast_strdupa(var->value);
         } else if (!strcasecmp(var->name, "bookId")) {
            ast_copy_string(bookid, var->value, sizeof(bookid));
         } else if (!strcasecmp(var->name, "opts")) {
            ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
         } else if (!strcasecmp(var->name, "maxusers")) {
            maxusers = atoi(var->value);
         } else if (!strcasecmp(var->name, "adminopts")) {
            ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
         } else if (!strcasecmp(var->name, "recordingfilename")) {
            ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
         } else if (!strcasecmp(var->name, "recordingformat")) {
            ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
         } else if (!strcasecmp(var->name, "endtime")) {
            struct ast_tm endtime_tm;
            ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
            endtime = ast_mktime(&endtime_tm, NULL);
         }
      }

      ast_variables_destroy(origvar);

      cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);

      if (cnf) {
         struct ast_flags tmp_flags;

         cnf->maxusers = maxusers;
         cnf->endalert = endalert;
         cnf->endtime = endtime.tv_sec;
         cnf->useropts = ast_strdup(useropts);
         cnf->adminopts = ast_strdup(adminopts);
         cnf->bookid = ast_strdup(bookid);
         cnf->recordingfilename = ast_strdup(recordingfilename);
         cnf->recordingformat = ast_strdup(recordingformat);

         /* Parse the other options into confflags -- need to do this in two
          * steps, because the parse_options routine zeroes the buffer. */
         ast_app_parse_options(meetme_opts, &tmp_flags, optargs, useropts);
         ast_copy_flags(confflags, &tmp_flags, tmp_flags.flags);

         if (strchr(cnf->useropts, 'r')) {
            if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */
               ast_channel_lock(chan);
               if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
                  ast_free(cnf->recordingfilename);
                  cnf->recordingfilename = ast_strdup(var2);
               }
               ast_channel_unlock(chan);
               if (ast_strlen_zero(cnf->recordingfilename)) {
                  snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, chan->uniqueid);
                  ast_free(cnf->recordingfilename);
                  cnf->recordingfilename = ast_strdup(recordingtmp);
               }
            }
            if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */
               ast_channel_lock(chan);
               if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
                  ast_free(cnf->recordingformat);
                  cnf->recordingformat = ast_strdup(var2);
               }
               ast_channel_unlock(chan);
               if (ast_strlen_zero(cnf->recordingformat)) {
                  ast_free(cnf->recordingformat);
                  cnf->recordingformat = ast_strdup("wav");
               }
            }
            ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
         }
      }
   }

   if (cnf) {
      if (confflags && !cnf->chan &&
          !ast_test_flag(confflags, CONFFLAG_QUIET) &&
          ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
         ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
         ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
      }

      if (confflags && !cnf->chan &&
          ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
         ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
      }
   }

   return cnf;
}
static struct ast_conf_user* find_user ( struct ast_conference conf,
char *  callerident 
) [static, read]

Definition at line 4100 of file app_meetme.c.

References ao2_find, user, and ast_conference::usercontainer.

Referenced by admin_exec().

{
   struct ast_conf_user *user = NULL;
   int cid;
   
   sscanf(callerident, "%30i", &cid);
   if (conf && callerident) {
      user = ao2_find(conf->usercontainer, &cid, 0);
      /* reference decremented later in admin_exec */
      return user;
   }
   return NULL;
}
static const char* get_announce_filename ( enum announcetypes  type) [static]

Definition at line 1947 of file app_meetme.c.

References CONF_HASJOIN, and CONF_HASLEFT.

Referenced by announce_thread().

{
   switch (type) {
   case CONF_HASLEFT:
      return "conf-hasleft";
      break;
   case CONF_HASJOIN:
      return "conf-hasjoin";
      break;
   default:
      return "";
   }
}
static char* istalking ( int  x) [static]

Definition at line 885 of file app_meetme.c.

Referenced by meetme_show_cmd().

{
   if (x > 0)
      return "(talking)";
   else if (x < 0)
      return "(unmonitored)";
   else 
      return "(not talking)";
}
static int load_config ( int  reload) [static]

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

{
   load_config_meetme();

   if (reload && sla.thread != AST_PTHREADT_NULL) {
      sla_queue_event(SLA_EVENT_RELOAD);
      ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
         "and will be completed when the system is idle.\n");
      return 0;
   }
   
   return sla_load_config(0);
}
static void load_config_meetme ( void  ) [static]

Definition at line 4629 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, LOG_WARNING, and val.

Referenced by load_config().

{
   struct ast_config *cfg;
   struct ast_flags config_flags = { 0 };
   const char *val;

   if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
      return;
   } else if (cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
      return;
   }

   audio_buffers = DEFAULT_AUDIO_BUFFERS;

   /*  Scheduling support is off by default */
   rt_schedule = 0;
   fuzzystart = 0;
   earlyalert = 0;
   endalert = 0;
   extendby = 0;

   /*  Logging of participants defaults to ON for compatibility reasons */
   rt_log_members = 1;  

   if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
      if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
         ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
         audio_buffers = DEFAULT_AUDIO_BUFFERS;
      } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
         ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
            DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
         audio_buffers = DEFAULT_AUDIO_BUFFERS;
      }
      if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
         ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
   }

   if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
      rt_schedule = ast_true(val);
   if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
      rt_log_members = ast_true(val);
   if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
      if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
         ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
         fuzzystart = 0;
      } 
   }
   if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
      if ((sscanf(val, "%30d", &earlyalert) != 1)) {
         ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
         earlyalert = 0;
      } 
   }
   if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
      if ((sscanf(val, "%30d", &endalert) != 1)) {
         ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
         endalert = 0;
      } 
   }
   if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
      if ((sscanf(val, "%30d", &extendby) != 1)) {
         ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
         extendby = 0;
      } 
   }

   ast_config_destroy(cfg);
}
static int load_module ( void  ) [static]

Definition at line 6660 of file app_meetme.c.

References action_meetmelist(), action_meetmemute(), action_meetmeunmute(), admin_exec(), ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_realtime_require_field(), ast_register_application_xml, channel_admin_exec(), conf_exec(), count_exec(), EVENT_FLAG_CALL, EVENT_FLAG_REPORTING, load_config(), meetmestate(), RQ_UINTEGER1, RQ_UINTEGER2, sla_state(), sla_station_exec(), and sla_trunk_exec().

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

Definition at line 1408 of file app_meetme.c.

References admin_exec(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_debug, ast_free, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd(), ast_cli_args::fd, ast_cli_args::line, MAX_CONFNUM, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

{
   /* Process the command */
   struct ast_str *cmdline = NULL;
   int i = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "meetme {lock|unlock|mute|unmute|kick}";
      e->usage =
         "Usage: meetme (un)lock|(un)mute|kick <confno> <usernumber>\n"
         "       Executes a command for the conference or on a conferee\n";
      return NULL;
   case CLI_GENERATE:
      return complete_meetmecmd(a->line, a->word, a->pos, a->n);
   }

   if (a->argc > 8)
      ast_cli(a->fd, "Invalid Arguments.\n");
   /* Check for length so no buffer will overflow... */
   for (i = 0; i < a->argc; i++) {
      if (strlen(a->argv[i]) > 100)
         ast_cli(a->fd, "Invalid Arguments.\n");
   }

   /* Max confno length */
   if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
      return CLI_FAILURE;
   }

   if (a->argc < 1) {
      ast_free(cmdline);
      return CLI_SHOWUSAGE;
   }

   ast_str_set(&cmdline, 0, "%s", a->argv[2]);  /* Argv 2: conference number */
   if (strstr(a->argv[1], "lock")) {
      if (strcmp(a->argv[1], "lock") == 0) {
         /* Lock */
         ast_str_append(&cmdline, 0, ",L");
      } else {
         /* Unlock */
         ast_str_append(&cmdline, 0, ",l");
      }
   } else if (strstr(a->argv[1], "mute")) { 
      if (a->argc < 4) {
         ast_free(cmdline);
         return CLI_SHOWUSAGE;
      }
      if (strcmp(a->argv[1], "mute") == 0) {
         /* Mute */
         if (strcmp(a->argv[3], "all") == 0) {
            ast_str_append(&cmdline, 0, ",N");
         } else {
            ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);  
         }
      } else {
         /* Unmute */
         if (strcmp(a->argv[3], "all") == 0) {
            ast_str_append(&cmdline, 0, ",n");
         } else {
            ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
         }
      }
   } else if (strcmp(a->argv[1], "kick") == 0) {
      if (a->argc < 4) {
         ast_free(cmdline);
         return CLI_SHOWUSAGE;
      }
      if (strcmp(a->argv[3], "all") == 0) {
         /* Kick all */
         ast_str_append(&cmdline, 0, ",K");
      } else {
         /* Kick a single user */
         ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
      }
   } else {
      ast_free(cmdline);
      return CLI_SHOWUSAGE;
   }

   ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));

   admin_exec(NULL, ast_str_buffer(cmdline));
   ast_free(cmdline);

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

Definition at line 1250 of file app_meetme.c.

References admin_exec(), 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_debug, ast_free, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_str_buffer(), ast_str_create(), ast_str_set(), ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd(), CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_cli_args::fd, ast_conference::isdynamic, istalking(), ast_conf_user::jointime, ast_cli_args::line, ast_conference::locked, ast_conference::markedusers, MAX_CONFNUM, MC_DATA_FORMAT, MC_HEADER_FORMAT, ast_cli_args::n, ast_channel::name, ast_cli_args::pos, S_OR, sec, ast_conference::start, ast_conf_user::talking, total, ast_cli_entry::usage, user, ast_conf_user::user_no, ast_conference::usercontainer, ast_conf_user::userflags, ast_conference::users, and ast_cli_args::word.

{
   /* Process the command */
   struct ast_conf_user *user;
   struct ast_conference *cnf;
   int hr, min, sec;
   int i = 0, total = 0;
   time_t now;
   struct ast_str *cmdline = NULL;
#define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s  %-8s  %-6s\n"
#define MC_DATA_FORMAT "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s  %-6s\n"

   switch (cmd) {
   case CLI_INIT:
      e->command = "meetme list [concise]";
      e->usage =
         "Usage: meetme list [concise] <confno> \n"
         "       List all or a specific conference.\n";
      return NULL;
   case CLI_GENERATE:
      return complete_meetmecmd(a->line, a->word, a->pos, a->n);
   }

   /* Check for length so no buffer will overflow... */
   for (i = 0; i < a->argc; i++) {
      if (strlen(a->argv[i]) > 100)
         ast_cli(a->fd, "Invalid Arguments.\n");
   }

   /* Max confno length */
   if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
      return CLI_FAILURE;
   }

   if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], "concise"))) {
      /* List all the conferences */   
      int concise = (a->argc == 3 && !strcasecmp(a->argv[2], "concise"));
      now = time(NULL);
      AST_LIST_LOCK(&confs);
      if (AST_LIST_EMPTY(&confs)) {
         if (!concise) {
            ast_cli(a->fd, "No active MeetMe conferences.\n");
         }
         AST_LIST_UNLOCK(&confs);
         ast_free(cmdline);
         return CLI_SUCCESS;
      }
      if (!concise) {
         ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
      }
      AST_LIST_TRAVERSE(&confs, cnf, list) {
         if (cnf->markedusers == 0) {
            ast_str_set(&cmdline, 0, "N/A ");
         } else {
            ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
         }
         hr = (now - cnf->start) / 3600;
         min = ((now - cnf->start) % 3600) / 60;
         sec = (now - cnf->start) % 60;
         if (!concise) {
            ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, ast_str_buffer(cmdline), hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
         } else {
            ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
               cnf->confno,
               cnf->users,
               cnf->markedusers,
               hr, min, sec,
               cnf->isdynamic,
               cnf->locked);
         }

         total += cnf->users;
      }
      AST_LIST_UNLOCK(&confs);
      if (!concise) {
         ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
      }
      ast_free(cmdline);
      return CLI_SUCCESS;
   } else if (strcmp(a->argv[1], "list") == 0) {
      struct ao2_iterator user_iter;
      int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
      /* List all the users in a conference */
      if (AST_LIST_EMPTY(&confs)) {
         if (!concise) {
            ast_cli(a->fd, "No active MeetMe conferences.\n");
         }
         ast_free(cmdline);
         return CLI_SUCCESS;  
      }
      /* Find the right conference */
      AST_LIST_LOCK(&confs);
      AST_LIST_TRAVERSE(&confs, cnf, list) {
         if (strcmp(cnf->confno, a->argv[2]) == 0) {
            break;
         }
      }
      if (!cnf) {
         if (!concise)
            ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
         AST_LIST_UNLOCK(&confs);
         ast_free(cmdline);
         return CLI_SUCCESS;
      }
      /* Show all the users */
      time(&now);
      user_iter = ao2_iterator_init(cnf->usercontainer, 0);
      while((user = ao2_iterator_next(&user_iter))) {
         hr = (now - user->jointime) / 3600;
         min = ((now - user->jointime) % 3600) / 60;
         sec = (now - user->jointime) % 60;
         if (!concise) {
            ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
               user->user_no,
               S_OR(user->chan->cid.cid_num, "<unknown>"),
               S_OR(user->chan->cid.cid_name, "<no name>"),
               user->chan->name,
               user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
               user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
               user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
               user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
               istalking(user->talking), hr, min, sec); 
         } else {
            ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
               user->user_no,
               S_OR(user->chan->cid.cid_num, ""),
               S_OR(user->chan->cid.cid_name, ""),
               user->chan->name,
               user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
               user->userflags  & CONFFLAG_MONITOR ? "1" : "",
               user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
               user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
               user->talking, hr, min, sec);
         }
         ao2_ref(user, -1);
      }
      ao2_iterator_destroy(&user_iter);
      if (!concise) {
         ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
      }
      AST_LIST_UNLOCK(&confs);
      ast_free(cmdline);
      return CLI_SUCCESS;
   }
   if (a->argc < 2) {
      ast_free(cmdline);
      return CLI_SHOWUSAGE;
   }

   ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));

   admin_exec(NULL, ast_str_buffer(cmdline));
   ast_free(cmdline);

   return CLI_SUCCESS;
}
static int meetmemute ( struct mansession s,
const struct message m,
int  mute 
) [static]

Definition at line 4393 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, ast_conf_user::list, LOG_NOTICE, ast_channel::name, ast_channel::uniqueid, user, ast_conf_user::user_no, and ast_conference::usercontainer.

Referenced by action_meetmemute(), and action_meetmeunmute().

{
   struct ast_conference *conf;
   struct ast_conf_user *user;
   const char *confid = astman_get_header(m, "Meetme");
   char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
   int userno;

   if (ast_strlen_zero(confid)) {
      astman_send_error(s, m, "Meetme conference not specified");
      return 0;
   }

   if (ast_strlen_zero(userid)) {
      astman_send_error(s, m, "Meetme user number not specified");
      return 0;
   }

   userno = strtoul(userid, &userid, 10);

   if (*userid) {
      astman_send_error(s, m, "Invalid user number");
      return 0;
   }

   /* Look in the conference list */
   AST_LIST_LOCK(&confs);
   AST_LIST_TRAVERSE(&confs, conf, list) {
      if (!strcmp(confid, conf->confno))
         break;
   }

   if (!conf) {
      AST_LIST_UNLOCK(&confs);
      astman_send_error(s, m, "Meetme conference does not exist");
      return 0;
   }

   user = ao2_find(conf->usercontainer, &userno, 0);

   if (!user) {
      AST_LIST_UNLOCK(&confs);
      astman_send_error(s, m, "User number not found");
      return 0;
   }

   if (mute)
      user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
   else
      user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */

   AST_LIST_UNLOCK(&confs);

   ast_log(LOG_NOTICE, "Requested to %smute conf %s user %d userchan %s uniqueid %s\n", mute ? "" : "un", conf->confno, user->user_no, user->chan->name, user->chan->uniqueid);

   ao2_ref(user, -1);
   astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
   return 0;
}
static enum ast_device_state meetmestate ( const char *  data) [static]

Callback for devicestate providers.

Definition at line 4607 of file app_meetme.c.

References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_conference::confno, ast_conference::list, and ast_conference::users.

Referenced by load_module().

{
   struct ast_conference *conf;

   /* Find conference */
   AST_LIST_LOCK(&confs);
   AST_LIST_TRAVERSE(&confs, conf, list) {
      if (!strcmp(data, conf->confno))
         break;
   }
   AST_LIST_UNLOCK(&confs);
   if (!conf)
      return AST_DEVICE_INVALID;


   /* SKREP to fill */
   if (!conf->users)
      return AST_DEVICE_NOT_INUSE;

   return AST_DEVICE_INUSE;
}
static struct sla_ringing_trunk* queue_ringing_trunk ( struct sla_trunk trunk) [static, read]

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

{
   struct sla_ringing_trunk *ringing_trunk;

   if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
      return NULL;
   
   ringing_trunk->trunk = trunk;
   ringing_trunk->ring_begin = ast_tvnow();

   sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);

   ast_mutex_lock(&sla.lock);
   AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
   ast_mutex_unlock(&sla.lock);

   sla_queue_event(SLA_EVENT_RINGING_TRUNK);

   return ringing_trunk;
}
static void * recordthread ( void *  args) [static]

Definition at line 4542 of file app_meetme.c.

References ast_closestream(), AST_FILE_MODE, AST_FRAME_BITS, AST_FRAME_VOICE, ast_frdup(), ast_frfree, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_stopstream(), ast_waitfor(), ast_writefile(), ast_writestream(), f, ast_frame::flags, ast_frame::frametype, ast_conference::lchan, ast_conference::listenlock, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, ast_conference::origframe, ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, s, and ast_conference::transframe.

{
   struct ast_conference *cnf = args;
   struct ast_frame *f = NULL;
   int flags;
   struct ast_filestream *s = NULL;
   int res = 0;
   int x;
   const char *oldrecordingfilename = NULL;

   if (!cnf || !cnf->lchan) {
      pthread_exit(0);
   }

   ast_stopstream(cnf->lchan);
   flags = O_CREAT | O_TRUNC | O_WRONLY;


   cnf->recording = MEETME_RECORD_ACTIVE;
   while (ast_waitfor(cnf->lchan, -1) > -1) {
      if (cnf->recording == MEETME_RECORD_TERMINATE) {
         AST_LIST_LOCK(&confs);
         AST_LIST_UNLOCK(&confs);
         break;
      }
      if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
         s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
         oldrecordingfilename = cnf->recordingfilename;
      }
      
      f = ast_read(cnf->lchan);
      if (!f) {
         res = -1;
         break;
      }
      if (f->frametype == AST_FRAME_VOICE) {
         ast_mutex_lock(&cnf->listenlock);
         for (x = 0; x < AST_FRAME_BITS; x++) {
            /* Free any translations that have occured */
            if (cnf->transframe[x]) {
               ast_frfree(cnf->transframe[x]);
               cnf->transframe[x] = NULL;
            }
         }
         if (cnf->origframe)
            ast_frfree(cnf->origframe);
         cnf->origframe = ast_frdup(f);
         ast_mutex_unlock(&cnf->listenlock);
         if (s)
            res = ast_writestream(s, f);
         if (res) {
            ast_frfree(f);
            break;
         }
      }
      ast_frfree(f);
   }
   cnf->recording = MEETME_RECORD_OFF;
   if (s)
      ast_closestream(s);
   
   pthread_exit(0);
}
static int reload ( void  ) [static]

Definition at line 6689 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

{
   ast_unload_realtime("meetme");
   return load_config(1);
}
static void reset_volumes ( struct ast_conf_user user) [static]

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

{
   signed char zero_volume = 0;

   ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
   ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
}
static int rt_extend_conf ( char *  confno) [static]

Definition at line 1869 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

{
   char currenttime[32];
   char endtime[32];
   struct timeval now;
   struct ast_tm tm;
   struct ast_variable *var, *orig_var;
   char bookid[51];

   if (!extendby) {
      return 0;
   }

   now = ast_tvnow();

   ast_localtime(&now, &tm, NULL);
   ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);

   var = ast_load_realtime("meetme", "confno",
      confno, "startTime<= ", currenttime,
      "endtime>= ", currenttime, NULL);

   orig_var = var;

   /* Identify the specific RealTime conference */
   while (var) {
      if (!strcasecmp(var->name, "bookid")) {
         ast_copy_string(bookid, var->value, sizeof(bookid));
      }
      if (!strcasecmp(var->name, "endtime")) {
         ast_copy_string(endtime, var->value, sizeof(endtime));
      }

      var = var->next;
   }
   ast_variables_destroy(orig_var);

   ast_strptime(endtime, DATE_FORMAT, &tm);
   now = ast_mktime(&tm, NULL);

   now.tv_sec += extendby;

   ast_localtime(&now, &tm, NULL);
   ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
   strcat(currenttime, "0"); /* Seconds needs to be 00 */

   var = ast_load_realtime("meetme", "confno",
      confno, "startTime<= ", currenttime,
      "endtime>= ", currenttime, NULL);

   /* If there is no conflict with extending the conference, update the DB */
   if (!var) {
      ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
      ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
      return 0;

   }

   ast_variables_destroy(var);
   return -1;
}
static void* run_station ( void *  data) [static]

Definition at line 4856 of file app_meetme.c.

References sla_trunk::active_stations, admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_cond_signal(), ast_dial_destroy(), ast_dial_join(), ast_free, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), build_conf(), sla_trunk_ref::chan, run_station_args::cond, run_station_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, sla_station::dial, dispose_conf(), ast_flags::flags, sla_trunk::hold_stations, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, run_station_args::station, sla_trunk_ref::trunk, and run_station_args::trunk_ref.

Referenced by sla_handle_dial_state_event().

{
   struct sla_station *station;
   struct sla_trunk_ref *trunk_ref;
   struct ast_str *conf_name = ast_str_create(16);
   struct ast_flags conf_flags = { 0 };
   struct ast_conference *conf;

   {
      struct run_station_args *args = data;
      station = args->station;
      trunk_ref = args->trunk_ref;
      ast_mutex_lock(args->cond_lock);
      ast_cond_signal(args->cond);
      ast_mutex_unlock(args->cond_lock);
      /* args is no longer valid here. */
   }

   ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
   ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
   ast_set_flag(&conf_flags, 
      CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
   answer_trunk_chan(trunk_ref->chan);
   conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan);
   if (conf) {
      conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
      dispose_conf(conf);
      conf = NULL;
   }
   trunk_ref->chan = NULL;
   if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
      trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
      ast_str_append(&conf_name, 0, ",K");
      admin_exec(NULL, ast_str_buffer(conf_name));
      trunk_ref->trunk->hold_stations = 0;
      sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
   }

   ast_dial_join(station->dial);
   ast_dial_destroy(station->dial);
   station->dial = NULL;
   ast_free(conf_name);

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

Definition at line 2023 of file app_meetme.c.

References ast_conference::confno, EVENT_FLAG_CALL, manager_event, ast_channel::name, ast_channel::uniqueid, and ast_conf_user::user_no.

Referenced by set_user_talking().

{
   manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
         "Channel: %s\r\n"
         "Uniqueid: %s\r\n"
         "Meetme: %s\r\n"
         "Usernum: %d\r\n"
         "Status: %s\r\n",
         chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
}
static int set_listen_volume ( struct ast_conf_user user,
int  volume 
) [static]

Definition at line 934 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

{
   char gain_adjust;

   /* attempt to make the adjustment in the channel driver;
      if successful, don't adjust in the frame reading routine
   */
   gain_adjust = gain_map[volume + 5];

   return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
}
static int set_talk_volume ( struct ast_conf_user user,
int  volume 
) [static]

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

{
   char gain_adjust;

   /* attempt to make the adjustment in the channel driver;
      if successful, don't adjust in the frame reading routine
   */
   gain_adjust = gain_map[volume + 5];

   return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
}
static void set_user_talking ( struct ast_channel chan,
struct ast_conference conf,
struct ast_conf_user user,
int  talking,
int  monitor 
) [static]

Definition at line 2034 of file app_meetme.c.

References send_talking_event(), and ast_conf_user::talking.

Referenced by conf_run().

{
   int last_talking = user->talking;
   if (last_talking == talking)
      return;

   user->talking = talking;

   if (monitor) {
      /* Check if talking state changed. Take care of -1 which means unmonitored */
      int was_talking = (last_talking > 0);
      int now_talking = (talking > 0);
      if (was_talking != now_talking) {
         send_talking_event(chan, conf, user, now_talking);
      }
   }
}
static void sla_add_trunk_to_station ( struct sla_station station,
struct ast_variable var 
) [static]

Definition at line 6316 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_trunk::num_stations, sla_trunk_ref::ring_delay, sla_trunk_ref::ring_timeout, sla_create_station_ref(), SLA_TRUNK_STATE_IDLE, sla_trunk_ref::state, sla_trunk::stations, strsep(), sla_station::trunks, and ast_variable::value.

Referenced by sla_build_station().

{
   struct sla_trunk *trunk;
   struct sla_trunk_ref *trunk_ref;
   struct sla_station_ref *station_ref;
   char *trunk_name, *options, *cur;

   options = ast_strdupa(var->value);
   trunk_name = strsep(&options, ",");
   
   AST_RWLIST_RDLOCK(&sla_trunks);
   AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
      if (!strcasecmp(trunk->name, trunk_name))
         break;
   }

   AST_RWLIST_UNLOCK(&sla_trunks);
   if (!trunk) {
      ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
      return;
   }
   if (!(trunk_ref = create_trunk_ref(trunk)))
      return;
   trunk_ref->state = SLA_TRUNK_STATE_IDLE;

   while ((cur = strsep(&options, ","))) {
      char *name, *value = cur;
      name = strsep(&value, "=");
      if (!strcasecmp(name, "ringtimeout")) {
         if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
            ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
               "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
            trunk_ref->ring_timeout = 0;
         }
      } else if (!strcasecmp(name, "ringdelay")) {
         if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
            ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
               "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
            trunk_ref->ring_delay = 0;
         }
      } else {
         ast_log(LOG_WARNING, "Invalid option '%s' for "
            "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
      }
   }

   if (!(station_ref = sla_create_station_ref(station))) {
      ast_free(trunk_ref);
      return;
   }
   ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
   AST_RWLIST_WRLOCK(&sla_trunks);
   AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
   AST_RWLIST_UNLOCK(&sla_trunks);
   AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
}
static int sla_build_station ( struct ast_config cfg,
const char *  cat 
) [static]

Definition at line 6373 of file app_meetme.c.

References ast_add_extension2(), ast_calloc, ast_context_find_or_create(), ast_free, ast_free_ptr, AST_LIST_TRAVERSE, ast_log(), AST_MAX_APP, AST_MAX_EXTENSION, AST_RWLIST_INSERT_TAIL, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), context, destroy_station(), exten, sla_station::hold_access, ast_variable::lineno, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, PRIORITY_HINT, sla_station::ring_delay, sla_station::ring_timeout, sla_add_trunk_to_station(), SLA_CONFIG_FILE, SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, sla_trunk_ref::trunk, sla_station::trunks, ast_variable::value, and var.

Referenced by sla_load_config().

{
   struct sla_station *station;
   struct ast_variable *var;
   const char *dev;

   if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
      ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
      return -1;
   }

   if (!(station = ast_calloc(1, sizeof(*station))))
      return -1;
   if (ast_string_field_init(station, 32)) {
      ast_free(station);
      return -1;
   }

   ast_string_field_set(station, name, cat);
   ast_string_field_set(station, device, dev);

   for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
      if (!strcasecmp(var->name, "trunk"))
         sla_add_trunk_to_station(station, var);
      else if (!strcasecmp(var->name, "autocontext"))
         ast_string_field_set(station, autocontext, var->value);
      else if (!strcasecmp(var->name, "ringtimeout")) {
         if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
            ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
               var->value, station->name);
            station->ring_timeout = 0;
         }
      } else if (!strcasecmp(var->name, "ringdelay")) {
         if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
            ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
               var->value, station->name);
            station->ring_delay = 0;
         }
      } else if (!strcasecmp(var->name, "hold")) {
         if (!strcasecmp(var->value, "private"))
            station->hold_access = SLA_HOLD_PRIVATE;
         else if (!strcasecmp(var->value, "open"))
            station->hold_access = SLA_HOLD_OPEN;
         else {
            ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
               var->value, station->name);
         }

      } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
         ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
            var->name, var->lineno, SLA_CONFIG_FILE);
      }
   }

   if (!ast_strlen_zero(station->autocontext)) {
      struct ast_context *context;
      struct sla_trunk_ref *trunk_ref;
      context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
      if (!context) {
         ast_log(LOG_ERROR, "Failed to automatically find or create "
            "context '%s' for SLA!\n", station->autocontext);
         destroy_station(station);
         return -1;
      }
      /* The extension for when the handset goes off-hook.
       * exten => station1,1,SLAStation(station1) */
      if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
         NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
         ast_log(LOG_ERROR, "Failed to automatically create extension "
            "for trunk '%s'!\n", station->name);
         destroy_station(station);
         return -1;
      }
      AST_RWLIST_RDLOCK(&sla_trunks);
      AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
         char exten[AST_MAX_EXTENSION];
         char hint[AST_MAX_APP];
         snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
         snprintf(hint, sizeof(hint), "SLA:%s", exten);
         /* Extension for this line button 
          * exten => station1_line1,1,SLAStation(station1_line1) */
         if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
            NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
            ast_log(LOG_ERROR, "Failed to automatically create extension "
               "for trunk '%s'!\n", station->name);
            destroy_station(station);
            return -1;
         }
         /* Hint for this line button 
          * exten => station1_line1,hint,SLA:station1_line1 */
         if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
            NULL, NULL, hint, NULL, NULL, sla_registrar)) {
            ast_log(LOG_ERROR, "Failed to automatically create hint "
               "for trunk '%s'!\n", station->name);
            destroy_station(station);
            return -1;
         }
      }
      AST_RWLIST_UNLOCK(&sla_trunks);
   }

   AST_RWLIST_WRLOCK(&sla_stations);
   AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
   AST_RWLIST_UNLOCK(&sla_stations);

   return 0;
}
static int sla_build_trunk ( struct ast_config cfg,
const char *  cat 
) [static]

Definition at line 6238 of file app_meetme.c.

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

Referenced by sla_load_config().

{
   struct sla_trunk *trunk;
   struct ast_variable *var;
   const char *dev;

   if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
      ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
      return -1;
   }

   if (sla_check_device(dev)) {
      ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
         cat, dev);
      return -1;
   }

   if (!(trunk = ast_calloc(1, sizeof(*trunk))))
      return -1;
   if (ast_string_field_init(trunk, 32)) {
      ast_free(trunk);
      return -1;
   }

   ast_string_field_set(trunk, name, cat);
   ast_string_field_set(trunk, device, dev);

   for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
      if (!strcasecmp(var->name, "autocontext"))
         ast_string_field_set(trunk, autocontext, var->value);
      else if (!strcasecmp(var->name, "ringtimeout")) {
         if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
            ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
               var->value, trunk->name);
            trunk->ring_timeout = 0;
         }
      } else if (!strcasecmp(var->name, "barge"))
         trunk->barge_disabled = ast_false(var->value);
      else if (!strcasecmp(var->name, "hold")) {
         if (!strcasecmp(var->value, "private"))
            trunk->hold_access = SLA_HOLD_PRIVATE;
         else if (!strcasecmp(var->value, "open"))
            trunk->hold_access = SLA_HOLD_OPEN;
         else {
            ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
               var->value, trunk->name);
         }
      } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
         ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
            var->name, var->lineno, SLA_CONFIG_FILE);
      }
   }

   if (!ast_strlen_zero(trunk->autocontext)) {
      struct ast_context *context;
      context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
      if (!context) {
         ast_log(LOG_ERROR, "Failed to automatically find or create "
            "context '%s' for SLA!\n", trunk->autocontext);
         destroy_trunk(trunk);
         return -1;
      }
      if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
         NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
         ast_log(LOG_ERROR, "Failed to automatically create extension "
            "for trunk '%s'!\n", trunk->name);
         destroy_trunk(trunk);
         return -1;
      }
   }

   AST_RWLIST_WRLOCK(&sla_trunks);
   AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
   AST_RWLIST_UNLOCK(&sla_trunks);

   return 0;
}
static int sla_calc_station_delays ( unsigned int *  timeout) [static]

Calculate the ring delay for a station.

Note:
Assumes sla.lock is locked

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

{
   struct sla_station *station;
   int res = 0;

   AST_LIST_TRAVERSE(&sla_stations, station, entry) {
      struct sla_ringing_trunk *ringing_trunk;
      int time_left;

      /* Ignore stations already ringing */
      if (sla_check_ringing_station(station))
         continue;

      /* Ignore stations already on a call */
      if (sla_check_inuse_station(station))
         continue;

      /* Ignore stations that don't have one of their trunks ringing */
      if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
         continue;

      if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
         continue;

      /* If there is no time left, then the station needs to start ringing.
       * Return non-zero so that an event will be queued up an event to 
       * make that happen. */
      if (time_left <= 0) {
         res = 1;
         continue;
      }

      if (time_left < *timeout)
         *timeout = time_left;
   }

   return res;
}
static int sla_calc_station_timeouts ( unsigned int *  timeout) [static]

Process station ring timeouts.

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

Definition at line 5386 of file app_meetme.c.

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_ringing_station::ring_begin, sla_ringing_trunk::ring_begin, sla_station::ring_timeout, sla_trunk_ref::ring_timeout, sla, SLA_STATION_HANGUP_TIMEOUT, sla_stop_ringing_station(), sla_station_ref::station, sla_ringing_station::station, sla_ringing_trunk::timed_out_stations, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, and sla_station::trunks.

Referenced by sla_process_timers().

{
   struct sla_ringing_trunk *ringing_trunk;
   struct sla_ringing_station *ringing_station;
   int res = 0;

   AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
      unsigned int ring_timeout = 0;
      int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
      struct sla_trunk_ref *trunk_ref;

      /* If there are any ring timeouts specified for a specific trunk
       * on the station, then use the highest per-trunk ring timeout.
       * Otherwise, use the ring timeout set for the entire station. */
      AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
         struct sla_station_ref *station_ref;
         int trunk_time_elapsed, trunk_time_left;

         AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
            if (ringing_trunk->trunk == trunk_ref->trunk)
               break;
         }
         if (!ringing_trunk)
            continue;

         /* If there is a trunk that is ringing without a timeout, then the
          * only timeout that could matter is a global station ring timeout. */
         if (!trunk_ref->ring_timeout)
            break;

         /* This trunk on this station is ringing and has a timeout.
          * However, make sure this trunk isn't still ringing from a
          * previous timeout.  If so, don't consider it. */
         AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
            if (station_ref->station == ringing_station->station)
               break;
         }
         if (station_ref)
            continue;

         trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
         trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
         if (trunk_time_left > final_trunk_time_left)
            final_trunk_time_left = trunk_time_left;
      }

      /* No timeout was found for ringing trunks, and no timeout for the entire station */
      if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
         continue;

      /* Compute how much time is left for a global station timeout */
      if (ringing_station->station->ring_timeout) {
         ring_timeout = ringing_station->station->ring_timeout;
         time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
         time_left = (ring_timeout * 1000) - time_elapsed;
      }

      /* If the time left based on the per-trunk timeouts is smaller than the
       * global station ring timeout, use that. */
      if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
         time_left = final_trunk_time_left;

      /* If there is no time left, the station needs to stop ringing */
      if (time_left <= 0) {
         AST_LIST_REMOVE_CURRENT(entry);
         sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
         res = 1;
         continue;
      }

      /* There is still some time left for this station to ring, so save that
       * timeout if it is the first event scheduled to occur */
      if (time_left < *timeout)
         *timeout = time_left;
   }
   AST_LIST_TRAVERSE_SAFE_END;

   return res;
}
static int sla_calc_trunk_timeouts ( unsigned int *  timeout) [static]

Process trunk ring timeouts.

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

Definition at line 5356 of file app_meetme.c.

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_trunk::chan, pbx_builtin_setvar_helper(), sla_ringing_trunk::ring_begin, sla_trunk::ring_timeout, sla, sla_stop_ringing_trunk(), and sla_ringing_trunk::trunk.

Referenced by sla_process_timers().

{
   struct sla_ringing_trunk *ringing_trunk;
   int res = 0;

   AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
      int time_left, time_elapsed;
      if (!ringing_trunk->trunk->ring_timeout)
         continue;
      time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
      time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
      if (time_left <= 0) {
         pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
         AST_LIST_REMOVE_CURRENT(entry);
         sla_stop_ringing_trunk(ringing_trunk);
         res = 1;
         continue;
      }
      if (time_left < *timeout)
         *timeout = time_left;
   }
   AST_LIST_TRAVERSE_SAFE_END;

   return res;
}
static void sla_change_trunk_state ( const struct sla_trunk trunk,
enum sla_trunk_state  state,
enum sla_which_trunk_refs  inactive_only,
const struct sla_trunk_ref exclude 
) [static]

Definition at line 4824 of file app_meetme.c.

References ast_devstate_changed(), AST_LIST_TRAVERSE, sla_trunk_ref::chan, sla_state_to_devstate(), sla_trunk_ref::state, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by dial_trunk(), queue_ringing_trunk(), run_station(), sla_handle_dial_state_event(), sla_handle_hold_event(), sla_station_exec(), sla_stop_ringing_trunk(), and sla_trunk_exec().

{
   struct sla_station *station;
   struct sla_trunk_ref *trunk_ref;

   AST_LIST_TRAVERSE(&sla_stations, station, entry) {
      AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
         if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
            || trunk_ref == exclude)
            continue;
         trunk_ref->state = state;
         ast_devstate_changed(sla_state_to_devstate(state), 
            "SLA:%s_%s", station->name, trunk->name);
         break;
      }
   }
}
static int sla_check_device ( const char *  device) [static]

Definition at line 6225 of file app_meetme.c.

References ast_strdupa, ast_strlen_zero(), and strsep().

Referenced by sla_build_trunk().

{
   char *tech, *tech_data;

   tech_data = ast_strdupa(device);
   tech = strsep(&tech_data, "/");

   if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
      return -1;

   return 0;
}
static int sla_check_failed_station ( const struct sla_station station) [static]

Check to see if this station has failed to be dialed in the past minute.

Note:
assumes sla.lock is locked

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

{
   struct sla_failed_station *failed_station;
   int res = 0;

   AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
      if (station != failed_station->station)
         continue;
      if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
         AST_LIST_REMOVE_CURRENT(entry);
         ast_free(failed_station);
         break;
      }
      res = 1;
   }
   AST_LIST_TRAVERSE_SAFE_END

   return res;
}
static int sla_check_inuse_station ( const struct sla_station station) [static]

Check to see if a station is in use.

Definition at line 5190 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla_trunk_ref::chan, and sla_station::trunks.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

{
   struct sla_trunk_ref *trunk_ref;

   AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
      if (trunk_ref->chan)
         return 1;
   }

   return 0;
}
static void sla_check_reload ( void  ) [static]

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

Definition at line 5548 of file app_meetme.c.

References ast_free, AST_LIST_EMPTY, ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_RDLOCK, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, sla_trunk::ref_count, sla_station::ref_count, sla, and sla_load_config().

Referenced by sla_thread().

{
   struct sla_station *station;
   struct sla_trunk *trunk;

   ast_mutex_lock(&sla.lock);

   if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
      || !AST_LIST_EMPTY(&sla.ringing_stations)) {
      ast_mutex_unlock(&sla.lock);
      return;
   }

   AST_RWLIST_RDLOCK(&sla_stations);
   AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
      if (station->ref_count)
         break;
   }
   AST_RWLIST_UNLOCK(&sla_stations);
   if (station) {
      ast_mutex_unlock(&sla.lock);
      return;
   }

   AST_RWLIST_RDLOCK(&sla_trunks);
   AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
      if (trunk->ref_count)
         break;
   }
   AST_RWLIST_UNLOCK(&sla_trunks);
   if (trunk) {
      ast_mutex_unlock(&sla.lock);
      return;
   }

   /* We need to actually delete the previous versions of trunks and stations now */
   AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_stations, station, entry) {
      AST_RWLIST_REMOVE_CURRENT(entry);
      ast_free(station);
   }
   AST_RWLIST_TRAVERSE_SAFE_END;

   AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_trunks, trunk, entry) {
      AST_RWLIST_REMOVE_CURRENT(entry);
      ast_free(trunk);
   }
   AST_RWLIST_TRAVERSE_SAFE_END;

   /* yay */
   sla_load_config(1);
   sla.reload = 0;

   ast_mutex_unlock(&sla.lock);
}
static int sla_check_ringing_station ( const struct sla_station station) [static]

Check to see if this station is already ringing.

Note:
Assumes sla.lock is locked

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

{
   struct sla_ringing_station *ringing_station;

   AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
      if (station == ringing_station->station)
         return 1;
   }

   return 0;
}
static int sla_check_station_delay ( struct sla_station station,
struct sla_ringing_trunk ringing_trunk 
) [static]

Calculate the ring delay for a given ringing trunk on a station.

Parameters:
stationthe station
ringing_trunkthe 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 5220 of file app_meetme.c.

References ast_tvdiff_ms(), ast_tvnow(), sla_ringing_trunk::ring_begin, sla_station::ring_delay, sla_trunk_ref::ring_delay, sla_choose_ringing_trunk(), sla_find_trunk_ref(), and sla_ringing_trunk::trunk.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

{
   struct sla_trunk_ref *trunk_ref;
   unsigned int delay = UINT_MAX;
   int time_left, time_elapsed;

   if (!ringing_trunk)
      ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
   else
      trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);

   if (!ringing_trunk || !trunk_ref)
      return delay;

   /* If this station has a ring delay specific to the highest priority
    * ringing trunk, use that.  Otherwise, use the ring delay specified
    * globally for the station. */
   delay = trunk_ref->ring_delay;
   if (!delay)
      delay = station->ring_delay;
   if (!delay)
      return INT_MAX;

   time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
   time_left = (delay * 1000) - time_elapsed;

   return time_left;
}
static int sla_check_station_hold_access ( const struct sla_trunk trunk,
const struct sla_station station 
) [static]

Definition at line 4729 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla_station::hold_access, SLA_HOLD_PRIVATE, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, sla_station_ref::station, sla_trunk::stations, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_find_trunk_ref_byname().

{
   struct sla_station_ref *station_ref;
   struct sla_trunk_ref *trunk_ref;

   /* For each station that has this call on hold, check for private hold. */
   AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
      AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
         if (trunk_ref->trunk != trunk || station_ref->station == station)
            continue;
         if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
            station_ref->station->hold_access == SLA_HOLD_PRIVATE)
            return 1;
         return 0;
      }
   }

   return 0;
}
static int sla_check_timed_out_station ( const struct sla_ringing_trunk ringing_trunk,
const struct sla_station station 
) [static]

Check to see if dialing this station already timed out for this ringing trunk.

Note:
Assumes sla.lock is locked

Definition at line 4960 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla_station_ref::station, and sla_ringing_trunk::timed_out_stations.

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

{
   struct sla_station_ref *timed_out_station;

   AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
      if (station == timed_out_station->station)
         return 1;
   }

   return 0;
}
static struct sla_trunk_ref* sla_choose_idle_trunk ( const struct sla_station station) [static, read]

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

Definition at line 5786 of file app_meetme.c.

References AST_LIST_TRAVERSE, SLA_TRUNK_STATE_IDLE, sla_trunk_ref::state, and sla_station::trunks.

Referenced by sla_station_exec().

{
   struct sla_trunk_ref *trunk_ref = NULL;

   AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
      if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
         break;
   }

   return trunk_ref;
}
static struct sla_ringing_trunk* sla_choose_ringing_trunk ( struct sla_station station,
struct sla_trunk_ref **  trunk_ref,
int  rm 
) [static, read]

Choose the highest priority ringing trunk for a station.

Parameters:
stationthe station
removeremove the ringing trunk once selected
trunk_refa 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 4981 of file app_meetme.c.

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

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

{
   struct sla_trunk_ref *s_trunk_ref;
   struct sla_ringing_trunk *ringing_trunk = NULL;

   AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
      AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
         /* Make sure this is the trunk we're looking for */
         if (s_trunk_ref->trunk != ringing_trunk->trunk)
            continue;

         /* This trunk on the station is ringing.  But, make sure this station
          * didn't already time out while this trunk was ringing. */
         if (sla_check_timed_out_station(ringing_trunk, station))
            continue;

         if (rm)
            AST_LIST_REMOVE_CURRENT(entry);

         if (trunk_ref)
            *trunk_ref = s_trunk_ref;

         break;
      }
      AST_LIST_TRAVERSE_SAFE_END;
   
      if (ringing_trunk)
         break;
   }

   return ringing_trunk;
}
static struct sla_ringing_station* sla_create_ringing_station ( struct sla_station station) [static, read]

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

{
   struct sla_ringing_station *ringing_station;

   if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
      return NULL;

   ringing_station->station = station;
   ringing_station->ring_begin = ast_tvnow();

   return ringing_station;
}
static struct sla_station_ref* sla_create_station_ref ( struct sla_station station) [static, read]

Definition at line 4782 of file app_meetme.c.

References ast_calloc, and sla_station_ref::station.

Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().

{
   struct sla_station_ref *station_ref;

   if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
      return NULL;

   station_ref->station = station;

   return station_ref;
}
static void sla_destroy ( void  ) [static]
static void sla_dial_state_callback ( struct ast_dial dial) [static]

Definition at line 4952 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

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

References AST_RWLIST_TRAVERSE.

Referenced by sla_station_exec().

{
   struct sla_station *station = NULL;

   AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
      if (!strcasecmp(station->name, name))
         break;
   }

   return station;
}
static struct sla_trunk* sla_find_trunk ( const char *  name) [static, read]

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 4702 of file app_meetme.c.

References AST_RWLIST_TRAVERSE.

Referenced by sla_trunk_exec().

{
   struct sla_trunk *trunk = NULL;

   AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
      if (!strcasecmp(trunk->name, name))
         break;
   }

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

Definition at line 5202 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_check_station_delay().

{
   struct sla_trunk_ref *trunk_ref = NULL;

   AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
      if (trunk_ref->trunk == trunk)
         break;
   }

   return trunk_ref;
}
static struct sla_trunk_ref* sla_find_trunk_ref_byname ( const struct sla_station station,
const char *  name 
) [static, read]

Find a trunk reference on a station by name.

Parameters:
stationthe station
namethe 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 4757 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla_trunk::barge_disabled, sla_trunk::hold_access, sla_trunk::hold_stations, sla_check_station_hold_access(), SLA_HOLD_PRIVATE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_UP, sla_trunk_ref::state, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_station_exec().

{
   struct sla_trunk_ref *trunk_ref = NULL;

   AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
      if (strcasecmp(trunk_ref->trunk->name, name))
         continue;

      if ( (trunk_ref->trunk->barge_disabled 
         && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
         (trunk_ref->trunk->hold_stations 
         && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
         && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
         sla_check_station_hold_access(trunk_ref->trunk, station) ) 
      {
         trunk_ref = NULL;
      }

      break;
   }

   return trunk_ref;
}
static void sla_handle_dial_state_event ( void  ) [static]

Definition at line 5015 of file app_meetme.c.

References ALL_TRUNK_REFS, answer_trunk_chan(), ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), ast_debug, ast_dial_answered(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_state(), ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_detached_background, sla_trunk::chan, sla_trunk_ref::chan, run_station_args::cond, cond, run_station_args::cond_lock, sla_station::dial, 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().

{
   struct sla_ringing_station *ringing_station;

   AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
      struct sla_trunk_ref *s_trunk_ref = NULL;
      struct sla_ringing_trunk *ringing_trunk = NULL;
      struct run_station_args args;
      enum ast_dial_result dial_res;
      pthread_t dont_care;
      ast_mutex_t cond_lock;
      ast_cond_t cond;

      switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
      case AST_DIAL_RESULT_HANGUP:
      case AST_DIAL_RESULT_INVALID:
      case AST_DIAL_RESULT_FAILED:
      case AST_DIAL_RESULT_TIMEOUT:
      case AST_DIAL_RESULT_UNANSWERED:
         AST_LIST_REMOVE_CURRENT(entry);
         sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
         break;
      case AST_DIAL_RESULT_ANSWERED:
         AST_LIST_REMOVE_CURRENT(entry);
         /* Find the appropriate trunk to answer. */
         ast_mutex_lock(&sla.lock);
         ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
         ast_mutex_unlock(&sla.lock);
         if (!ringing_trunk) {
            ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
            break;
         }
         /* Track the channel that answered this trunk */
         s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
         /* Actually answer the trunk */
         answer_trunk_chan(ringing_trunk->trunk->chan);
         sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
         /* Now, start a thread that will connect this station to the trunk.  The rest of
          * the code here sets up the thread and ensures that it is able to save the arguments
          * before they are no longer valid since they are allocated on the stack. */
         args.trunk_ref = s_trunk_ref;
         args.station = ringing_station->station;
         args.cond = &cond;
         args.cond_lock = &cond_lock;
         ast_free(ringing_trunk);
         ast_free(ringing_station);
         ast_mutex_init(&cond_lock);
         ast_cond_init(&cond, NULL);
         ast_mutex_lock(&cond_lock);
         ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
         ast_cond_wait(&cond, &cond_lock);
         ast_mutex_unlock(&cond_lock);
         ast_mutex_destroy(&cond_lock);
         ast_cond_destroy(&cond);
         break;
      case AST_DIAL_RESULT_TRYING:
      case AST_DIAL_RESULT_RINGING:
      case AST_DIAL_RESULT_PROGRESS:
      case AST_DIAL_RESULT_PROCEEDING:
         break;
      }
      if (dial_res == AST_DIAL_RESULT_ANSWERED) {
         /* Queue up reprocessing ringing trunks, and then ringing stations again */
         sla_queue_event(SLA_EVENT_RINGING_TRUNK);
         sla_queue_event(SLA_EVENT_DIAL_STATE);
         break;
      }
   }
   AST_LIST_TRAVERSE_SAFE_END;
}
static void sla_handle_hold_event ( struct sla_event event) [static]
static void sla_handle_ringing_trunk_event ( void  ) [static]

Definition at line 5322 of file app_meetme.c.

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

Referenced by sla_thread().

{
   ast_mutex_lock(&sla.lock);
   sla_ring_stations();
   ast_mutex_unlock(&sla.lock);

   /* Find stations that shouldn't be ringing anymore. */
   sla_hangup_stations();
}
static void sla_hangup_stations ( void  ) [static]

Definition at line 5294 of file app_meetme.c.

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

Referenced by sla_handle_ringing_trunk_event().

{
   struct sla_trunk_ref *trunk_ref;
   struct sla_ringing_station *ringing_station;

   AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
      AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
         struct sla_ringing_trunk *ringing_trunk;
         ast_mutex_lock(&sla.lock);
         AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
            if (trunk_ref->trunk == ringing_trunk->trunk)
               break;
         }
         ast_mutex_unlock(&sla.lock);
         if (ringing_trunk)
            break;
      }
      if (!trunk_ref) {
         AST_LIST_REMOVE_CURRENT(entry);
         ast_dial_join(ringing_station->station->dial);
         ast_dial_destroy(ringing_station->station->dial);
         ringing_station->station->dial = NULL;
         ast_free(ringing_station);
      }
   }
   AST_LIST_TRAVERSE_SAFE_END
}
static const char* sla_hold_str ( unsigned int  hold_access) [static]

Definition at line 1497 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

{
   const char *hold = "Unknown";

   switch (hold_access) {
   case SLA_HOLD_OPEN:
      hold = "Open";
      break;
   case SLA_HOLD_PRIVATE:
      hold = "Private";
   default:
      break;
   }

   return hold;
}
static int sla_load_config ( int  reload) [static]

Definition at line 6481 of file app_meetme.c.

References ast_category_browse(), ast_cond_init(), ast_config_destroy(), ast_config_load, AST_LIST_EMPTY, ast_log(), ast_mutex_init(), ast_pthread_create, AST_PTHREADT_NULL, 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(), type, and val.

Referenced by load_config(), and sla_check_reload().

{
   struct ast_config *cfg;
   struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
   const char *cat = NULL;
   int res = 0;
   const char *val;

   if (!reload) {
      ast_mutex_init(&sla.lock);
      ast_cond_init(&sla.cond, NULL);
   }

   if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
      return 0; /* Treat no config as normal */
   } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
      return 0;
   } else if (cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format.  Aborting.\n");
      return 0;
   }

   if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
      sla.attempt_callerid = ast_true(val);

   while ((cat = ast_category_browse(cfg, cat)) && !res) {
      const char *type;
      if (!strcasecmp(cat, "general"))
         continue;
      if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
         ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
            SLA_CONFIG_FILE);
         continue;
      }
      if (!strcasecmp(type, "trunk"))
         res = sla_build_trunk(cfg, cat);
      else if (!strcasecmp(type, "station"))
         res = sla_build_station(cfg, cat);
      else {
         ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
            SLA_CONFIG_FILE, type);
      }
   }

   ast_config_destroy(cfg);

   /* Even if we don't have any stations, we may after a reload and we need to
    * be able to process the SLA_EVENT_RELOAD event in that case */
   if (sla.thread == AST_PTHREADT_NULL && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_trunks))) {
      ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
   }

   return res;
}
static int sla_process_timers ( struct timespec *  ts) [static]

Calculate the time until the next known event.

Note:
Called with sla.lock locked

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

{
   unsigned int timeout = UINT_MAX;
   struct timeval wait;
   unsigned int change_made = 0;

   /* Check for ring timeouts on ringing trunks */
   if (sla_calc_trunk_timeouts(&timeout))
      change_made = 1;

   /* Check for ring timeouts on ringing stations */
   if (sla_calc_station_timeouts(&timeout))
      change_made = 1;

   /* Check for station ring delays */
   if (sla_calc_station_delays(&timeout))
      change_made = 1;

   /* queue reprocessing of ringing trunks */
   if (change_made)
      sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);

   /* No timeout */
   if (timeout == UINT_MAX)
      return 0;

   if (ts) {
      wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
      ts->tv_sec = wait.tv_sec;
      ts->tv_nsec = wait.tv_usec * 1000;
   }

   return 1;
}
static void sla_queue_event ( enum sla_event_type  type) [static]
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 1816 of file app_meetme.c.

References ast_debug, AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdupa, ast_strlen_zero(), sla_trunk_ref::chan, ast_conference::confno, LOG_ERROR, sla_queue_event_full(), strsep(), sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by conf_run().

{
   struct sla_station *station;
   struct sla_trunk_ref *trunk_ref = NULL;
   char *trunk_name;

   trunk_name = ast_strdupa(conf->confno);
   strsep(&trunk_name, "_");
   if (ast_strlen_zero(trunk_name)) {
      ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
      return;
   }

   AST_RWLIST_RDLOCK(&sla_stations);
   AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
      AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
         if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
            break;
      }
      if (trunk_ref)
         break;
   }
   AST_RWLIST_UNLOCK(&sla_stations);

   if (!trunk_ref) {
      ast_debug(1, "Trunk not found for event!\n");
      return;
   }

   sla_queue_event_full(type, trunk_ref, station, 1);
}
static void sla_queue_event_full ( enum sla_event_type  type,
struct sla_trunk_ref trunk_ref,
struct sla_station station,
int  lock 
) [static]

Definition at line 1778 of file app_meetme.c.

References ast_calloc, ast_cond_signal(), AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, sla, sla_event::station, sla_event::trunk_ref, type, and sla_event::type.

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

{
   struct sla_event *event;

   if (sla.thread == AST_PTHREADT_NULL) {
      return;
   }

   if (!(event = ast_calloc(1, sizeof(*event))))
      return;

   event->type = type;
   event->trunk_ref = trunk_ref;
   event->station = station;

   if (!lock) {
      AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
      return;
   }

   ast_mutex_lock(&sla.lock);
   AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
   ast_cond_signal(&sla.cond);
   ast_mutex_unlock(&sla.lock);
}
static void sla_queue_event_nolock ( enum sla_event_type  type) [static]

Definition at line 1805 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

{
   sla_queue_event_full(type, NULL, NULL, 0);
}
static int sla_ring_station ( struct sla_ringing_trunk ringing_trunk,
struct sla_station station 
) [static]

Ring a station.

Note:
Assumes sla.lock is locked

Definition at line 5127 of file app_meetme.c.

References ast_calloc, ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_TRYING, ast_dial_run(), ast_dial_set_state_callback(), ast_free, AST_LIST_INSERT_HEAD, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvnow(), sla_trunk::chan, ast_channel::cid, ast_callerid::cid_name, cid_name, ast_callerid::cid_num, cid_num, sla_station::dial, sla_failed_station::last_try, sla, sla_create_ringing_station(), sla_dial_state_callback(), sla_failed_station::station, strsep(), and sla_ringing_trunk::trunk.

Referenced by sla_ring_stations().

{
   char *tech, *tech_data;
   struct ast_dial *dial;
   struct sla_ringing_station *ringing_station;
   const char *cid_name = NULL, *cid_num = NULL;
   enum ast_dial_result res;

   if (!(dial = ast_dial_create()))
      return -1;

   ast_dial_set_state_callback(dial, sla_dial_state_callback);
   tech_data = ast_strdupa(station->device);
   tech = strsep(&tech_data, "/");

   if (ast_dial_append(dial, tech, tech_data) == -1) {
      ast_dial_destroy(dial);
      return -1;
   }

   if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
      cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
      ast_free(ringing_trunk->trunk->chan->cid.cid_name);
      ringing_trunk->trunk->chan->cid.cid_name = NULL;
   }
   if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
      cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
      ast_free(ringing_trunk->trunk->chan->cid.cid_num);
      ringing_trunk->trunk->chan->cid.cid_num = NULL;
   }

   res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
   
   if (cid_name)
      ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
   if (cid_num)
      ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
   
   if (res != AST_DIAL_RESULT_TRYING) {
      struct sla_failed_station *failed_station;
      ast_dial_destroy(dial);
      if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
         return -1;
      failed_station->station = station;
      failed_station->last_try = ast_tvnow();
      AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
      return -1;
   }
   if (!(ringing_station = sla_create_ringing_station(station))) {
      ast_dial_join(dial);
      ast_dial_destroy(dial);
      return -1;
   }

   station->dial = dial;

   AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);

   return 0;
}
static void sla_ring_stations ( void  ) [static]

Ring stations based on current set of ringing trunks.

Note:
Assumes that sla.lock is locked

Definition at line 5253 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla, sla_check_failed_station(), sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), sla_check_timed_out_station(), sla_ring_station(), sla_station_ref::station, sla_trunk::stations, and sla_ringing_trunk::trunk.

Referenced by sla_handle_ringing_trunk_event().

{
   struct sla_station_ref *station_ref;
   struct sla_ringing_trunk *ringing_trunk;

   /* Make sure that every station that uses at least one of the ringing
    * trunks, is ringing. */
   AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
      AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
         int time_left;

         /* Is this station already ringing? */
         if (sla_check_ringing_station(station_ref->station))
            continue;

         /* Is this station already in a call? */
         if (sla_check_inuse_station(station_ref->station))
            continue;

         /* Did we fail to dial this station earlier?  If so, has it been
          * a minute since we tried? */
         if (sla_check_failed_station(station_ref->station))
            continue;

         /* If this station already timed out while this trunk was ringing,
          * do not dial it again for this ringing trunk. */
         if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
            continue;

         /* Check for a ring delay in progress */
         time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
         if (time_left != INT_MAX && time_left > 0)
            continue;

         /* It is time to make this station begin to ring.  Do it! */
         sla_ring_station(ringing_trunk, station_ref->station);
      }
   }
   /* Now, all of the stations that should be ringing, are ringing. */
}
static char* sla_show_stations ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1579 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, sla_station::hold_access, sla_trunk_ref::ring_delay, sla_station::ring_delay, sla_trunk_ref::ring_timeout, sla_station::ring_timeout, S_OR, sla_hold_str(), sla_trunk_ref::state, sla_trunk_ref::trunk, sla_station::trunks, trunkstate2str(), and ast_cli_entry::usage.

{
   const struct sla_station *station;

   switch (cmd) {
   case CLI_INIT:
      e->command = "sla show stations";
      e->usage =
         "Usage: sla show stations\n"
         "       This will list all stations defined in sla.conf\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   ast_cli(a->fd, "\n" 
               "=============================================================\n"
               "=== Configured SLA Stations =================================\n"
               "=============================================================\n"
               "===\n");
   AST_RWLIST_RDLOCK(&sla_stations);
   AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
      struct sla_trunk_ref *trunk_ref;
      char ring_timeout[16] = "(none)";
      char ring_delay[16] = "(none)";
      if (station->ring_timeout) {
         snprintf(ring_timeout, sizeof(ring_timeout), 
            "%u", station->ring_timeout);
      }
      if (station->ring_delay) {
         snprintf(ring_delay, sizeof(ring_delay), 
            "%u", station->ring_delay);
      }
      ast_cli(a->fd, "=== ---------------------------------------------------------\n"
                  "=== Station Name:    %s\n"
                  "=== ==> Device:      %s\n"
                  "=== ==> AutoContext: %s\n"
                  "=== ==> RingTimeout: %s\n"
                  "=== ==> RingDelay:   %s\n"
                  "=== ==> HoldAccess:  %s\n"
                  "=== ==> Trunks ...\n",
                  station->name, station->device,
                  S_OR(station->autocontext, "(none)"), 
                  ring_timeout, ring_delay,
                  sla_hold_str(station->hold_access));
      AST_RWLIST_RDLOCK(&sla_trunks);
      AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
         if (trunk_ref->ring_timeout) {
            snprintf(ring_timeout, sizeof(ring_timeout),
               "%u", trunk_ref->ring_timeout);
         } else
            strcpy(ring_timeout, "(none)");
         if (trunk_ref->ring_delay) {
            snprintf(ring_delay, sizeof(ring_delay),
               "%u", trunk_ref->ring_delay);
         } else
            strcpy(ring_delay, "(none)");
            ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
                     "===       ==> State:       %s\n"
                     "===       ==> RingTimeout: %s\n"
                     "===       ==> RingDelay:   %s\n",
                     trunk_ref->trunk->name,
                     trunkstate2str(trunk_ref->state),
                     ring_timeout, ring_delay);
      }
      AST_RWLIST_UNLOCK(&sla_trunks);
      ast_cli(a->fd, "=== ---------------------------------------------------------\n"
                  "===\n");
   }
   AST_RWLIST_UNLOCK(&sla_stations);
   ast_cli(a->fd, "============================================================\n"
               "\n");

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

Definition at line 1514 of file app_meetme.c.

References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, sla_trunk::barge_disabled, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, sla_trunk::hold_access, sla_trunk::ring_timeout, S_OR, sla_hold_str(), sla_station_ref::station, sla_trunk::stations, and ast_cli_entry::usage.

{
   const struct sla_trunk *trunk;

   switch (cmd) {
   case CLI_INIT:
      e->command = "sla show trunks";
      e->usage =
         "Usage: sla show trunks\n"
         "       This will list all trunks defined in sla.conf\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   ast_cli(a->fd, "\n"
               "=============================================================\n"
               "=== Configured SLA Trunks ===================================\n"
               "=============================================================\n"
               "===\n");
   AST_RWLIST_RDLOCK(&sla_trunks);
   AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
      struct sla_station_ref *station_ref;
      char ring_timeout[16] = "(none)";
      if (trunk->ring_timeout)
         snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
      ast_cli(a->fd, "=== ---------------------------------------------------------\n"
                  "=== Trunk Name:       %s\n"
                  "=== ==> Device:       %s\n"
                  "=== ==> AutoContext:  %s\n"
                  "=== ==> RingTimeout:  %s\n"
                  "=== ==> BargeAllowed: %s\n"
                  "=== ==> HoldAccess:   %s\n"
                  "=== ==> Stations ...\n",
                  trunk->name, trunk->device, 
                  S_OR(trunk->autocontext, "(none)"), 
                  ring_timeout,
                  trunk->barge_disabled ? "No" : "Yes",
                  sla_hold_str(trunk->hold_access));
      AST_RWLIST_RDLOCK(&sla_stations);
      AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
         ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
      AST_RWLIST_UNLOCK(&sla_stations);
      ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
   }
   AST_RWLIST_UNLOCK(&sla_trunks);
   ast_cli(a->fd, "=============================================================\n\n");

   return CLI_SUCCESS;
}
static enum ast_device_state sla_state ( const char *  data) [static]

Definition at line 6119 of file app_meetme.c.

References AST_DEVICE_INVALID, AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_strdupa, buf, LOG_ERROR, sla_state_to_devstate(), sla_trunk_ref::state, strsep(), sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by load_module().

{
   char *buf, *station_name, *trunk_name;
   struct sla_station *station;
   struct sla_trunk_ref *trunk_ref;
   enum ast_device_state res = AST_DEVICE_INVALID;

   trunk_name = buf = ast_strdupa(data);
   station_name = strsep(&trunk_name, "_");

   AST_RWLIST_RDLOCK(&sla_stations);
   AST_LIST_TRAVERSE(&sla_stations, station, entry) {
      if (strcasecmp(station_name, station->name))
         continue;
      AST_RWLIST_RDLOCK(&sla_trunks);
      AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
         if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
            break;
      }
      if (!trunk_ref) {
         AST_RWLIST_UNLOCK(&sla_trunks);
         break;
      }
      res = sla_state_to_devstate(trunk_ref->state);
      AST_RWLIST_UNLOCK(&sla_trunks);
   }
   AST_RWLIST_UNLOCK(&sla_stations);

   if (res == AST_DEVICE_INVALID) {
      ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
         trunk_name, station_name);
   }

   return res;
}
static int sla_station_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 5798 of file app_meetme.c.

References sla_trunk::active_stations, admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), ast_answer(), ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), AST_CONTROL_UNHOLD, ast_debug, AST_DEVICE_INUSE, ast_devstate_changed(), ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_detached_background, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, ast_strdupa, ast_strlen_zero(), build_conf(), chan, sla_trunk_ref::chan, sla_trunk::chan, cond, dial_trunk_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dial_trunk(), dispose_conf(), ast_flags::flags, free, sla_trunk::hold_stations, LOG_NOTICE, LOG_WARNING, MAX_CONFNUM, sla_trunk::on_hold, pbx_builtin_setvar_helper(), sla_station::ref_count, sla, sla_change_trunk_state(), sla_choose_idle_trunk(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_find_station(), sla_find_trunk_ref_byname(), sla_queue_event(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, sla_trunk_ref::state, dial_trunk_args::station, strsep(), sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.

Referenced by load_module().

{
   char *station_name, *trunk_name;
   struct sla_station *station;
   struct sla_trunk_ref *trunk_ref = NULL;
   char conf_name[MAX_CONFNUM];
   struct ast_flags conf_flags = { 0 };
   struct ast_conference *conf;

   if (ast_strlen_zero(data)) {
      ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
      pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
      return 0;
   }

   trunk_name = ast_strdupa(data);
   station_name = strsep(&trunk_name, "_");

   if (ast_strlen_zero(station_name)) {
      ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
      pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
      return 0;
   }

   AST_RWLIST_RDLOCK(&sla_stations);
   station = sla_find_station(station_name);
   if (station)
      ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
   AST_RWLIST_UNLOCK(&sla_stations);

   if (!station) {
      ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
      pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
      sla_queue_event(SLA_EVENT_CHECK_RELOAD);
      return 0;
   }

   AST_RWLIST_RDLOCK(&sla_trunks);
   if (!ast_strlen_zero(trunk_name)) {
      trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
   } else
      trunk_ref = sla_choose_idle_trunk(station);
   AST_RWLIST_UNLOCK(&sla_trunks);

   if (!trunk_ref) {
      if (ast_strlen_zero(trunk_name))
         ast_log(LOG_NOTICE, "No trunks available for call.\n");
      else {
         ast_log(LOG_NOTICE, "Can't join existing call on trunk "
            "'%s' due to access controls.\n", trunk_name);
      }
      pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
      ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
      sla_queue_event(SLA_EVENT_CHECK_RELOAD);
      return 0;
   }

   if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
      if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
         sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
      else {
         trunk_ref->state = SLA_TRUNK_STATE_UP;
         ast_devstate_changed(AST_DEVICE_INUSE, 
            "SLA:%s_%s", station->name, trunk_ref->trunk->name);
      }
   } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
      struct sla_ringing_trunk *ringing_trunk;

      ast_mutex_lock(&sla.lock);
      AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
         if (ringing_trunk->trunk == trunk_ref->trunk) {
            AST_LIST_REMOVE_CURRENT(entry);
            break;
         }
      }
      AST_LIST_TRAVERSE_SAFE_END
      ast_mutex_unlock(&sla.lock);

      if (ringing_trunk) {
         answer_trunk_chan(ringing_trunk->trunk->chan);
         sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);

         free(ringing_trunk);

         /* Queue up reprocessing ringing trunks, and then ringing stations again */
         sla_queue_event(SLA_EVENT_RINGING_TRUNK);
         sla_queue_event(SLA_EVENT_DIAL_STATE);
      }
   }

   trunk_ref->chan = chan;

   if (!trunk_ref->trunk->chan) {
      ast_mutex_t cond_lock;
      ast_cond_t cond;
      pthread_t dont_care;
      struct dial_trunk_args args = {
         .trunk_ref = trunk_ref,
         .station = station,
         .cond_lock = &cond_lock,
         .cond = &cond,
      };
      sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
      /* Create a thread to dial the trunk and dump it into the conference.
       * However, we want to wait until the trunk has been dialed and the
       * conference is created before continuing on here. */
      ast_autoservice_start(chan);
      ast_mutex_init(&cond_lock);
      ast_cond_init(&cond, NULL);
      ast_mutex_lock(&cond_lock);
      ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
      ast_cond_wait(&cond, &cond_lock);
      ast_mutex_unlock(&cond_lock);
      ast_mutex_destroy(&cond_lock);
      ast_cond_destroy(&cond);
      ast_autoservice_stop(chan);
      if (!trunk_ref->trunk->chan) {
         ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
         pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
         sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
         trunk_ref->chan = NULL;
         ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
         sla_queue_event(SLA_EVENT_CHECK_RELOAD);
         return 0;
      }
   }

   if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
      trunk_ref->trunk->on_hold) {
      trunk_ref->trunk->on_hold = 0;
      ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
      sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
   }

   snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
   ast_set_flag(&conf_flags, 
      CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
   ast_answer(chan);
   conf = build_conf(conf_name, "", "", 0, 0, 1, chan);
   if (conf) {
      conf_run(chan, conf, conf_flags.flags, NULL);
      dispose_conf(conf);
      conf = NULL;
   }
   trunk_ref->chan = NULL;
   if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
      trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
      strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
      admin_exec(NULL, conf_name);
      trunk_ref->trunk->hold_stations = 0;
      sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
   }
   
   pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");

   ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
   sla_queue_event(SLA_EVENT_CHECK_RELOAD);

   return 0;
}
static void sla_stop_ringing_station ( struct sla_ringing_station ringing_station,
enum sla_station_hangup  hangup 
) [static]

Definition at line 4917 of file app_meetme.c.

References ast_dial_destroy(), ast_dial_join(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, sla_station::dial, sla, sla_create_station_ref(), SLA_STATION_HANGUP_NORMAL, sla_ringing_station::station, sla_ringing_trunk::timed_out_stations, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, and sla_station::trunks.

Referenced by sla_calc_station_timeouts(), and sla_handle_dial_state_event().

{
   struct sla_ringing_trunk *ringing_trunk;
   struct sla_trunk_ref *trunk_ref;
   struct sla_station_ref *station_ref;

   ast_dial_join(ringing_station->station->dial);
   ast_dial_destroy(ringing_station->station->dial);
   ringing_station->station->dial = NULL;

   if (hangup == SLA_STATION_HANGUP_NORMAL)
      goto done;

   /* If the station is being hung up because of a timeout, then add it to the
    * list of timed out stations on each of the ringing trunks.  This is so
    * that when doing further processing to figure out which stations should be
    * ringing, which trunk to answer, determining timeouts, etc., we know which
    * ringing trunks we should ignore. */
   AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
      AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
         if (ringing_trunk->trunk == trunk_ref->trunk)
            break;
      }
      if (!trunk_ref)
         continue;
      if (!(station_ref = sla_create_station_ref(ringing_station->station)))
         continue;
      AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
   }

done:
   ast_free(ringing_station);
}
static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk) [static]

Definition at line 4902 of file app_meetme.c.

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

Referenced by sla_calc_trunk_timeouts().

{
   char buf[80];
   struct sla_station_ref *station_ref;

   snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
   admin_exec(NULL, buf);
   sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);

   while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
      ast_free(station_ref);

   ast_free(ringing_trunk);
}
static void* sla_thread ( void *  data) [static]

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

{
   struct sla_failed_station *failed_station;
   struct sla_ringing_station *ringing_station;

   ast_mutex_lock(&sla.lock);

   while (!sla.stop) {
      struct sla_event *event;
      struct timespec ts = { 0, };
      unsigned int have_timeout = 0;

      if (AST_LIST_EMPTY(&sla.event_q)) {
         if ((have_timeout = sla_process_timers(&ts)))
            ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
         else
            ast_cond_wait(&sla.cond, &sla.lock);
         if (sla.stop)
            break;
      }

      if (have_timeout)
         sla_process_timers(NULL);

      while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
         ast_mutex_unlock(&sla.lock);
         switch (event->type) {
         case SLA_EVENT_HOLD:
            sla_handle_hold_event(event);
            break;
         case SLA_EVENT_DIAL_STATE:
            sla_handle_dial_state_event();
            break;
         case SLA_EVENT_RINGING_TRUNK:
            sla_handle_ringing_trunk_event();
            break;
         case SLA_EVENT_RELOAD:
            sla.reload = 1;
         case SLA_EVENT_CHECK_RELOAD:
            break;
         }
         ast_free(event);
         ast_mutex_lock(&sla.lock);
      }

      if (sla.reload) {
         sla_check_reload();
      }
   }

   ast_mutex_unlock(&sla.lock);

   while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
      ast_free(ringing_station);

   while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
      ast_free(failed_station);

   return NULL;
}
static int sla_trunk_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 6005 of file app_meetme.c.

References ALL_TRUNK_REFS, AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_free, ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, build_conf(), chan, sla_trunk::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, dispose_conf(), ast_flags::flags, LOG_ERROR, MAX_CONFNUM, sla_trunk::on_hold, OPT_ARG_ARRAY_SIZE, OPT_ARG_MOH_CLASS, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), queue_ringing_trunk(), sla_trunk::ref_count, sla, sla_change_trunk_state(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), SLA_TRUNK_OPT_ARG_ARRAY_SIZE, SLA_TRUNK_OPT_ARG_MOH_CLASS, SLA_TRUNK_OPT_MOH, sla_trunk_opts, SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by load_module().

{
   char conf_name[MAX_CONFNUM];
   struct ast_conference *conf;
   struct ast_flags conf_flags = { 0 };
   struct sla_trunk *trunk;
   struct sla_ringing_trunk *ringing_trunk;
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(trunk_name);
      AST_APP_ARG(options);
   );
   char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
   char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
   struct ast_flags opt_flags = { 0 };
   char *parse;

   if (ast_strlen_zero(data)) {
      ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
      return -1;
   }

   parse = ast_strdupa(data);
   AST_STANDARD_APP_ARGS(args, parse);
   if (args.argc == 2) {
      if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
         ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
         return -1;
      }
   }

   AST_RWLIST_RDLOCK(&sla_trunks);
   trunk = sla_find_trunk(args.trunk_name);
   if (trunk)
      ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
   AST_RWLIST_UNLOCK(&sla_trunks);

   if (!trunk) {
      ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
      pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
      sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
      return 0;
   }

   if (trunk->chan) {
      ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
         args.trunk_name);
      pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
      ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
      sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
      return 0;
   }

   trunk->chan = chan;

   if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
      pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
      ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
      sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
      return 0;
   }

   snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
   conf = build_conf(conf_name, "", "", 1, 1, 1, chan);
   if (!conf) {
      pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
      ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
      sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
      return 0;
   }
   ast_set_flag(&conf_flags, 
      CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);

   if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
      ast_indicate(chan, -1);
      ast_set_flag(&conf_flags, CONFFLAG_MOH);
      conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
   } else
      ast_indicate(chan, AST_CONTROL_RINGING);

   conf_run(chan, conf, conf_flags.flags, opts);
   dispose_conf(conf);
   conf = NULL;
   trunk->chan = NULL;
   trunk->on_hold = 0;

   sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);

   if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
      pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");

   /* Remove the entry from the list of ringing trunks if it is still there. */
   ast_mutex_lock(&sla.lock);
   AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
      if (ringing_trunk->trunk == trunk) {
         AST_LIST_REMOVE_CURRENT(entry);
         break;
      }
   }
   AST_LIST_TRAVERSE_SAFE_END;
   ast_mutex_unlock(&sla.lock);
   if (ringing_trunk) {
      ast_free(ringing_trunk);
      pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
      /* Queue reprocessing of ringing trunks to make stations stop ringing
       * that shouldn't be ringing after this trunk stopped. */
      sla_queue_event(SLA_EVENT_RINGING_TRUNK);
   }

   ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
   sla_queue_event(SLA_EVENT_CHECK_RELOAD);  

   return 0;
}
static const char* trunkstate2str ( enum sla_trunk_state  state) [static]

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

{
#define S(e) case e: return # e;
   switch (state) {
   S(SLA_TRUNK_STATE_IDLE)
   S(SLA_TRUNK_STATE_RINGING)
   S(SLA_TRUNK_STATE_UP)
   S(SLA_TRUNK_STATE_ONHOLD)
   S(SLA_TRUNK_STATE_ONHOLD_BYME)
   }
   return "Uknown State";
#undef S
}
static void tweak_listen_volume ( struct ast_conf_user user,
enum volume_action  action 
) [static]

Definition at line 993 of file app_meetme.c.

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

Referenced by admin_exec(), conf_run(), user_listen_voldown_cb(), and user_listen_volup_cb().

{
   tweak_volume(&user->listen, action);
   /* attempt to make the adjustment in the channel driver;
      if successful, don't adjust in the frame reading routine
   */
   if (!set_listen_volume(user, user->listen.desired))
      user->listen.actual = 0;
   else
      user->listen.actual = user->listen.desired;
}
static void tweak_talk_volume ( struct ast_conf_user user,
enum volume_action  action 
) [static]

Definition at line 981 of file app_meetme.c.

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

Referenced by admin_exec(), conf_run(), user_talk_voldown_cb(), and user_talk_volup_cb().

{
   tweak_volume(&user->talk, action);
   /* attempt to make the adjustment in the channel driver;
      if successful, don't adjust in the frame reading routine
   */
   if (!set_talk_volume(user, user->talk.desired))
      user->talk.actual = 0;
   else
      user->talk.actual = user->talk.desired;
}
static void tweak_volume ( struct volume vol,
enum volume_action  action 
) [static]

Definition at line 946 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

{
   switch (action) {
   case VOL_UP:
      switch (vol->desired) { 
      case 5:
         break;
      case 0:
         vol->desired = 2;
         break;
      case -2:
         vol->desired = 0;
         break;
      default:
         vol->desired++;
         break;
      }
      break;
   case VOL_DOWN:
      switch (vol->desired) {
      case -5:
         break;
      case 2:
         vol->desired = 0;
         break;
      case 0:
         vol->desired = -2;
         break;
      default:
         vol->desired--;
         break;
      }
   }
}
static int user_chan_cb ( void *  obj,
void *  args,
int  flags 
) [static]

Definition at line 4172 of file app_meetme.c.

References ast_conf_user::chan, CMP_MATCH, CMP_STOP, and ast_channel::name.

Referenced by channel_admin_exec().

{
   struct ast_conf_user *user = obj;
   const char *channel = args;

   if (!strcmp(user->chan->name, channel)) {
      return (CMP_MATCH | CMP_STOP);
   }

   return 0;
}
static int user_listen_voldown_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4144 of file app_meetme.c.

References tweak_listen_volume(), and VOL_DOWN.

Referenced by admin_exec().

{
   struct ast_conf_user *user = obj;
   tweak_listen_volume(user, VOL_DOWN);
   return 0;
}
static int user_listen_volup_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4137 of file app_meetme.c.

References tweak_listen_volume(), and VOL_UP.

Referenced by admin_exec().

{
   struct ast_conf_user *user = obj;
   tweak_listen_volume(user, VOL_UP);
   return 0;
}
static int user_max_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1059 of file app_meetme.c.

References ast_conf_user::user_no.

Referenced by admin_exec(), and conf_run().

{
   struct ast_conf_user *user = obj;
   int *max_no = arg;

   if (user->user_no > *max_no) {
      *max_no = user->user_no;
   }

   return 0;
}
static int user_no_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1047 of file app_meetme.c.

References CMP_MATCH, CMP_STOP, and ast_conf_user::user_no.

Referenced by build_conf().

{
   struct ast_conf_user *user = obj;
   int *user_no = arg;

   if (user->user_no == *user_no) {
      return (CMP_MATCH | CMP_STOP);
   }

   return 0;
}
static int user_reset_vol_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4165 of file app_meetme.c.

References reset_volumes().

Referenced by admin_exec().

{
   struct ast_conf_user *user = obj;
   reset_volumes(user);
   return 0;
}
static int user_set_kickme_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4114 of file app_meetme.c.

References ADMINFLAG_KICKME, and ast_conf_user::adminflags.

Referenced by admin_exec().

{
   struct ast_conf_user *user = obj;
   user->adminflags |= ADMINFLAG_KICKME;
   return 0;
}
static int user_set_muted_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4121 of file app_meetme.c.

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

Referenced by admin_exec().

{
   struct ast_conf_user *user = obj;
   if (!(user->userflags & CONFFLAG_ADMIN)) {
      user->adminflags |= ADMINFLAG_MUTED;
   }
   return 0;
}
static int user_set_unmuted_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4130 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, and ast_conf_user::adminflags.

Referenced by admin_exec().

{
   struct ast_conf_user *user = obj;
   user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
   return 0;
}
static int user_talk_voldown_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4158 of file app_meetme.c.

References tweak_talk_volume(), and VOL_DOWN.

Referenced by admin_exec().

{
   struct ast_conf_user *user = obj;
   tweak_talk_volume(user, VOL_DOWN);
   return 0;
}
static int user_talk_volup_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 4151 of file app_meetme.c.

References tweak_talk_volume(), and VOL_UP.

Referenced by admin_exec().

{
   struct ast_conf_user *user = obj;
   tweak_talk_volume(user, VOL_UP);
   return 0;
}

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "MeetMe conference bridge" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 6699 of file app_meetme.c.

const char* app = "MeetMe" [static]

Definition at line 568 of file app_meetme.c.

const char* app2 = "MeetMeCount" [static]

Definition at line 569 of file app_meetme.c.

const char* app3 = "MeetMeAdmin" [static]

Definition at line 570 of file app_meetme.c.

const char* app4 = "MeetMeChannelAdmin" [static]

Definition at line 571 of file app_meetme.c.

Definition at line 6699 of file app_meetme.c.

unsigned int attempt_callerid

Attempt to handle CallerID, even though it is known not to work properly in some situations.

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

Referenced by conf_run().

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1655 of file app_meetme.c.

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

Definition at line 652 of file app_meetme.c.

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

struct confs confs [static]
int earlyalert [static]

Definition at line 578 of file app_meetme.c.

Referenced by find_conf_realtime().

int endalert [static]

Definition at line 579 of file app_meetme.c.

Referenced by find_conf_realtime().

struct { ... } event_q
int extendby [static]

Definition at line 580 of file app_meetme.c.

Referenced by rt_extend_conf().

struct { ... } failed_stations
int fuzzystart [static]

Definition at line 577 of file app_meetme.c.

Referenced by find_conf_realtime().

char const gain_map[] [static]

Map 'volume' levels from -5 through +5 into decibel (dB) settings for channel drivers Note: these are not a straight linear-to-dB conversion... the numbers have been modified to give the user a better level of adjustability

Definition at line 867 of file app_meetme.c.

char mandescr_meetmelist[] = " *Conference: <confno>\n" [static]

Definition at line 4463 of file app_meetme.c.

Definition at line 6605 of file app_meetme.c.

struct ast_app_option meetme_opts[128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, } [static]

Definition at line 566 of file app_meetme.c.

Referenced by conf_exec(), and find_conf_realtime().

static int reload

A reload has been requested

reload: Part of Asterisk module interface ---

Definition at line 852 of file app_meetme.c.

Referenced by handle_cli_moh_reload(), handle_minivm_reload(), reload(), rpt_do_reload(), and show_console().

struct { ... } ringing_stations
struct { ... } ringing_trunks
int rt_log_members [static]

Definition at line 583 of file app_meetme.c.

int rt_schedule [static]

Definition at line 576 of file app_meetme.c.

const char sla_registrar[] = "SLA" [static]
struct sla_stations sla_stations [static]
struct ast_app_option sla_trunk_opts[128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, } [static]

Definition at line 6003 of file app_meetme.c.

Referenced by sla_trunk_exec().

struct sla_trunks sla_trunks [static]
const char* slastation_app = "SLAStation" [static]

Definition at line 572 of file app_meetme.c.

const char* slatrunk_app = "SLATrunk" [static]

Definition at line 573 of file app_meetme.c.

unsigned int stop