Sat Feb 11 06:33:46 2012

Asterisk developer's documentation


app_meetme.c File Reference

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

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

Include dependency graph for app_meetme.c:

Go to the source code of this file.

Data Structures

struct  announce_listitem
struct  ast_conf_user
 The MeetMe User object. More...
struct  ast_conference
 The MeetMe Conference object. More...
struct  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 CONFFLAG_INTROMSG   (1ULL << 32)
#define CONFFLAG_INTROUSER_VMREC   (1ULL << 33)
#define CONFFLAG_KILL_LAST_MAN_STANDING   ((uint64_t)1 << 34)
#define CONFFLAG_NO_AUDIO_UNTIL_UP   (1ULL << 31)
#define CONFIG_FILE_NAME   "meetme.conf"
#define DATE_FORMAT   "%Y-%m-%d %H:%M:%S"
#define DEFAULT_AUDIO_BUFFERS   32
#define MAX_CONFNUM   80
#define MAX_PIN   80
#define MAX_SETTINGS   (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)
#define MC_DATA_FORMAT   "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
#define MC_HEADER_FORMAT   "%-14s %-14s %-10s %-8s %-8s %-6s\n"
#define MEETME_DATA_EXPORT(MEMBER)
#define MEETME_DELAYDETECTENDTALK   1000
#define MEETME_DELAYDETECTTALK   300
#define MEETME_USER_DATA_EXPORT(MEMBER)
#define OPTIONS_LEN   100
#define S(e)   case e: return # e;
#define SLA_CONFIG_FILE   "sla.conf"

Enumerations

enum  {
  ADMINFLAG_MUTED = (1 << 1), ADMINFLAG_SELFMUTED = (1 << 2), ADMINFLAG_KICKME = (1 << 3), ADMINFLAG_T_REQUEST = (1 << 4),
  ADMINFLAG_HANGUP = (1 << 5)
}
enum  {
  CONFFLAG_ADMIN = (1 << 0), CONFFLAG_MONITOR = (1 << 1), CONFFLAG_KEYEXIT = (1 << 2), CONFFLAG_STARMENU = (1 << 3),
  CONFFLAG_TALKER = (1 << 4), CONFFLAG_QUIET = (1 << 5), CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6), CONFFLAG_AGI = (1 << 7),
  CONFFLAG_MOH = (1 << 8), CONFFLAG_MARKEDEXIT = (1 << 9), CONFFLAG_WAITMARKED = (1 << 10), CONFFLAG_EXIT_CONTEXT = (1 << 11),
  CONFFLAG_MARKEDUSER = (1 << 12), CONFFLAG_INTROUSER = (1 << 13), CONFFLAG_RECORDCONF = (1<< 14), CONFFLAG_MONITORTALKER = (1 << 15),
  CONFFLAG_DYNAMIC = (1 << 16), CONFFLAG_DYNAMICPIN = (1 << 17), CONFFLAG_EMPTY = (1 << 18), CONFFLAG_EMPTYNOPIN = (1 << 19),
  CONFFLAG_ALWAYSPROMPT = (1 << 20), CONFFLAG_OPTIMIZETALKER = (1 << 21), CONFFLAG_NOONLYPERSON = (1 << 22), CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
  CONFFLAG_STARTMUTED = (1 << 24), CONFFLAG_PASS_DTMF = (1 << 25), CONFFLAG_SLA_STATION = (1 << 26), CONFFLAG_SLA_TRUNK = (1 << 27),
  CONFFLAG_KICK_CONTINUE = (1 << 28), CONFFLAG_DURATION_STOP = (1 << 29), CONFFLAG_DURATION_LIMIT = (1 << 30)
}
enum  {
  OPT_ARG_WAITMARKED = 0, OPT_ARG_EXITKEYS = 1, OPT_ARG_DURATION_STOP = 2, OPT_ARG_DURATION_LIMIT = 3,
  OPT_ARG_MOH_CLASS = 4, OPT_ARG_INTROMSG = 5, OPT_ARG_INTROUSER_VMREC = 6, OPT_ARG_ARRAY_SIZE = 7
}
enum  { SLA_TRUNK_OPT_MOH = (1 << 0) }
enum  { SLA_TRUNK_OPT_ARG_MOH_CLASS = 0, SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1 }
enum  announcetypes { CONF_HASJOIN, CONF_HASLEFT }
enum  entrance_sound { ENTER, LEAVE }
enum  recording_state { MEETME_RECORD_OFF, MEETME_RECORD_STARTED, MEETME_RECORD_ACTIVE, MEETME_RECORD_TERMINATE }
enum  sla_event_type {
  SLA_EVENT_HOLD, SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, SLA_EVENT_RELOAD,
  SLA_EVENT_CHECK_RELOAD
}
 Event types that can be queued up for the SLA thread. More...
enum  sla_hold_access { SLA_HOLD_OPEN, SLA_HOLD_PRIVATE }
enum  sla_station_hangup { SLA_STATION_HANGUP_NORMAL, SLA_STATION_HANGUP_TIMEOUT }
enum  sla_trunk_state {
  SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, SLA_TRUNK_STATE_ONHOLD,
  SLA_TRUNK_STATE_ONHOLD_BYME
}
enum  sla_which_trunk_refs { ALL_TRUNK_REFS, INACTIVE_TRUNK_REFS }
enum  volume_action { VOL_UP, VOL_DOWN }

Functions

static void __fini_sla_stations (void)
static void __fini_sla_trunks (void)
static void __init_sla_stations (void)
static void __init_sla_trunks (void)
static void __reg_module (void)
static void __unreg_module (void)
static int acf_meetme_info (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_meetme_info_eval (const char *keyword, const struct ast_conference *conf)
static int action_meetmelist (struct mansession *s, const struct message *m)
static int action_meetmelistrooms (struct mansession *s, const struct message *m)
static int action_meetmemute (struct mansession *s, const struct message *m)
static int action_meetmeunmute (struct mansession *s, const struct message *m)
static int admin_exec (struct ast_channel *chan, const char *data)
 The MeetMeadmin application.
static void * announce_thread (void *data)
static void answer_trunk_chan (struct ast_channel *chan)
 AST_DATA_STRUCTURE (ast_conf_user, MEETME_USER_DATA_EXPORT)
 AST_DATA_STRUCTURE (ast_conference, MEETME_DATA_EXPORT)
static struct ast_conferencebuild_conf (const char *confno, const char *pin, const char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan, struct ast_test *test)
 Find or create a conference.
static int can_write (struct ast_channel *chan, struct ast_flags64 *confflags)
static int careful_write (int fd, unsigned char *data, int len, int block)
static int channel_admin_exec (struct ast_channel *chan, const char *data)
 The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command).
static char * complete_meetmecmd (const char *line, const char *word, int pos, int state)
static int conf_exec (struct ast_channel *chan, const char *data)
 The meetme() application.
static void conf_flush (int fd, struct ast_channel *chan)
static int conf_free (struct ast_conference *conf)
 Remove the conference from the list and free it.
static void conf_play (struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
static void conf_queue_dtmf (const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
static int conf_run (struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
static void conf_start_moh (struct ast_channel *chan, const char *musicclass)
static int count_exec (struct ast_channel *chan, const char *data)
 The MeetmeCount application.
static struct sla_trunk_refcreate_trunk_ref (struct sla_trunk *trunk)
static void destroy_station (struct sla_station *station)
static void destroy_trunk (struct sla_trunk *trunk)
static void * dial_trunk (void *data)
static int dispose_conf (struct ast_conference *conf)
 Decrement reference counts, as incremented by find_conf().
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags)
static struct ast_conferencefind_conf_realtime (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags, int *too_early, char **optargs)
static struct ast_conf_userfind_user (struct ast_conference *conf, const char *callerident)
static const char * get_announce_filename (enum announcetypes type)
static const char * istalking (int x)
static int load_config (int reload)
static void load_config_meetme (void)
static int load_module (void)
static char * meetme_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int meetme_data_provider_get (const struct ast_data_search *search, struct ast_data *data_root)
static char * meetme_show_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int meetmemute (struct mansession *s, const struct message *m, int mute)
static enum ast_device_state meetmestate (const char *data)
 Callback for devicestate providers.
static struct sla_ringing_trunkqueue_ringing_trunk (struct sla_trunk *trunk)
static void * recordthread (void *args)
static int reload (void)
static void reset_volumes (struct ast_conf_user *user)
static int rt_extend_conf (const char *confno)
static void * run_station (void *data)
static void send_talking_event (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
static int set_listen_volume (struct ast_conf_user *user, int volume)
static int set_talk_volume (struct ast_conf_user *user, int volume)
static void set_user_talking (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
static void sla_add_trunk_to_station (struct sla_station *station, struct ast_variable *var)
static int sla_build_station (struct ast_config *cfg, const char *cat)
static int sla_build_trunk (struct ast_config *cfg, const char *cat)
static int sla_calc_station_delays (unsigned int *timeout)
 Calculate the ring delay for a station.
static int sla_calc_station_timeouts (unsigned int *timeout)
 Process station ring timeouts.
static int sla_calc_trunk_timeouts (unsigned int *timeout)
 Process trunk ring timeouts.
static void sla_change_trunk_state (const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
static int sla_check_device (const char *device)
static int sla_check_failed_station (const struct sla_station *station)
 Check to see if this station has failed to be dialed in the past minute.
static int sla_check_inuse_station (const struct sla_station *station)
 Check to see if a station is in use.
static void sla_check_reload (void)
 Check if we can do a reload of SLA, and do it if we can.
static int sla_check_ringing_station (const struct sla_station *station)
 Check to see if this station is already ringing.
static int sla_check_station_delay (struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
 Calculate the ring delay for a given ringing trunk on a station.
static int sla_check_station_hold_access (const struct sla_trunk *trunk, const struct sla_station *station)
static int sla_check_timed_out_station (const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
 Check to see if dialing this station already timed out for this ringing trunk.
static struct sla_trunk_refsla_choose_idle_trunk (const struct sla_station *station)
 For a given station, choose the highest priority idle trunk.
static struct sla_ringing_trunksla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int rm)
 Choose the highest priority ringing trunk for a station.
static struct sla_ringing_stationsla_create_ringing_station (struct sla_station *station)
static struct sla_station_refsla_create_station_ref (struct sla_station *station)
static void sla_destroy (void)
static void sla_dial_state_callback (struct ast_dial *dial)
static struct sla_stationsla_find_station (const char *name)
 Find an SLA station by name.
static struct sla_trunksla_find_trunk (const char *name)
 Find an SLA trunk by name.
static struct sla_trunk_refsla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk)
static struct sla_trunk_refsla_find_trunk_ref_byname (const struct sla_station *station, const char *name)
 Find a trunk reference on a station by name.
static void sla_handle_dial_state_event (void)
static void sla_handle_hold_event (struct sla_event *event)
static void sla_handle_ringing_trunk_event (void)
static void sla_hangup_stations (void)
static const char * sla_hold_str (unsigned int hold_access)
static int sla_load_config (int reload)
static int sla_process_timers (struct timespec *ts)
 Calculate the time until the next known event.
static void sla_queue_event (enum sla_event_type type)
static void sla_queue_event_conf (enum sla_event_type type, struct ast_channel *chan, struct ast_conference *conf)
 Queue a SLA event from the conference.
static void sla_queue_event_full (enum sla_event_type type, struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
static void sla_queue_event_nolock (enum sla_event_type type)
static int sla_ring_station (struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
 Ring a station.
static void sla_ring_stations (void)
 Ring stations based on current set of ringing trunks.
static char * sla_show_stations (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * sla_show_trunks (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static enum ast_device_state sla_state (const char *data)
static enum ast_device_state sla_state_to_devstate (enum sla_trunk_state state)
static int sla_station_exec (struct ast_channel *chan, const char *data)
static void sla_stop_ringing_station (struct sla_ringing_station *ringing_station, enum sla_station_hangup hangup)
static void sla_stop_ringing_trunk (struct sla_ringing_trunk *ringing_trunk)
static void * sla_thread (void *data)
static int sla_trunk_exec (struct ast_channel *chan, const char *data)
static const char * trunkstate2str (enum sla_trunk_state state)
static void tweak_listen_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_talk_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_volume (struct volume *vol, enum volume_action action)
static int unload_module (void)
static int user_add_provider_cb (void *obj, void *arg, int flags)
static int user_chan_cb (void *obj, void *args, int flags)
static int user_listen_voldown_cb (void *obj, void *unused, int flags)
static int user_listen_volup_cb (void *obj, void *unused, int flags)
static int user_max_cmp (void *obj, void *arg, int flags)
static int user_no_cmp (void *obj, void *arg, int flags)
static int user_reset_vol_cb (void *obj, void *unused, int flags)
static int user_set_hangup_cb (void *obj, void *check_admin_arg, int flags)
static int user_set_kickme_cb (void *obj, void *check_admin_arg, int flags)
static int user_set_muted_cb (void *obj, void *check_admin_arg, int flags)
static int user_set_unmuted_cb (void *obj, void *check_admin_arg, int flags)
static int user_talk_voldown_cb (void *obj, void *unused, int flags)
static int user_talk_volup_cb (void *obj, void *unused, int flags)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "MeetMe conference bridge" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, }
static const char *const app = "MeetMe"
static const char *const app2 = "MeetMeCount"
static const char *const app3 = "MeetMeAdmin"
static const char *const app4 = "MeetMeChannelAdmin"
static struct ast_module_infoast_module_info = &__mod_info
static int audio_buffers
 The number of audio buffers to be allocated on pseudo channels when in a conference.
static struct ast_cli_entry cli_meetme []
static unsigned int conf_map [1024] = {0, }
static int earlyalert
static int endalert
static int extendby
static int fuzzystart
static const char gain_map []
 Map 'volume' levels from -5 through +5 into decibel (dB) settings for channel drivers.
static struct ast_data_handler meetme_data_provider
static struct ast_data_entry meetme_data_providers []
static struct ast_custom_function meetme_info_acf
static 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 }, [ 'G' ] = { .flag = (1ULL << 32) , .arg_index = OPT_ARG_INTROMSG + 1 }, [ 'v' ] = { .flag = (1ULL << 33) , .arg_index = OPT_ARG_INTROUSER_VMREC + 1 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'k' ] = { .flag = ((uint64_t)1 << 34) }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
static int rt_log_members
static int rt_schedule
struct {
   unsigned int   attempt_callerid:1
   ast_cond_t   cond
   struct {
      struct sla_event *   first
      struct sla_event *   last
   }   event_q
   struct {
      struct sla_failed_station *   first
      struct sla_failed_station *   last
   }   failed_stations
   ast_mutex_t   lock
   unsigned int   reload:1
   struct {
      struct sla_ringing_station *   first
      struct sla_ringing_station *   last
   }   ringing_stations
   struct {
      struct sla_ringing_trunk *   first
      struct sla_ringing_trunk *   last
   }   ringing_trunks
   unsigned int   stop:1
   pthread_t   thread
sla
 A structure for data used by the sla thread.
static const char sla_registrar [] = "SLA"
static struct ast_app_option sla_trunk_opts [128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, }
static const char *const slastation_app = "SLAStation"
static const char *const slatrunk_app = "SLATrunk"


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

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

#define CONF_SIZE   320

Definition at line 580 of file app_meetme.c.

#define CONFFLAG_INTROMSG   (1ULL << 32)

If set play an intro announcement at start of conference

Definition at line 645 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_INTROUSER_VMREC   (1ULL << 33)

Definition at line 646 of file app_meetme.c.

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

#define CONFFLAG_KILL_LAST_MAN_STANDING   ((uint64_t)1 << 34)

If there's only one person left in a conference when someone leaves, kill the conference

Definition at line 648 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_NO_AUDIO_UNTIL_UP   (1ULL << 31)

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

Definition at line 644 of file app_meetme.c.

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

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 540 of file app_meetme.c.

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

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

String format for scheduled conferences

Definition at line 547 of file app_meetme.c.

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

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 544 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

#define MAX_PIN   80

Definition at line 714 of file app_meetme.c.

Referenced by conf_exec(), and conf_get_pin().

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

Definition at line 718 of file app_meetme.c.

Referenced by conf_exec(), and find_conf().

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

Referenced by meetme_show_cmd().

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

Referenced by meetme_show_cmd().

#define MEETME_DATA_EXPORT ( MEMBER   ) 

Definition at line 7133 of file app_meetme.c.

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 559 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 558 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_USER_DATA_EXPORT ( MEMBER   ) 

Definition at line 7150 of file app_meetme.c.

#define OPTIONS_LEN   100

Definition at line 715 of file app_meetme.c.

Referenced by find_conf_realtime().

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

Referenced by sms_readfile(), and trunkstate2str().

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 541 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
ADMINFLAG_HANGUP  User will be leaving the conference

Definition at line 549 of file app_meetme.c.

00549      {
00550    ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
00551    ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
00552    ADMINFLAG_KICKME =    (1 << 3),  /*!< User has been kicked */
00553    /*! User has requested to speak */
00554    ADMINFLAG_T_REQUEST = (1 << 4),
00555    ADMINFLAG_HANGUP = (1 << 5),  /*!< User will be leaving the conference */
00556 };

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 

Definition at line 582 of file app_meetme.c.

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

anonymous enum

Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_EXITKEYS 
OPT_ARG_DURATION_STOP 
OPT_ARG_DURATION_LIMIT 
OPT_ARG_MOH_CLASS 
OPT_ARG_INTROMSG 
OPT_ARG_INTROUSER_VMREC 
OPT_ARG_ARRAY_SIZE 

Definition at line 650 of file app_meetme.c.

00650      {
00651    OPT_ARG_WAITMARKED = 0,
00652    OPT_ARG_EXITKEYS   = 1,
00653    OPT_ARG_DURATION_STOP = 2,
00654    OPT_ARG_DURATION_LIMIT = 3,
00655    OPT_ARG_MOH_CLASS = 4,
00656    OPT_ARG_INTROMSG = 5,
00657    OPT_ARG_INTROUSER_VMREC = 6,
00658    OPT_ARG_ARRAY_SIZE = 7,
00659 };

anonymous enum

Enumerator:
SLA_TRUNK_OPT_MOH 

Definition at line 6490 of file app_meetme.c.

06490      {
06491    SLA_TRUNK_OPT_MOH = (1 << 0),
06492 };

anonymous enum

Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 6494 of file app_meetme.c.

06494      {
06495    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
06496    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
06497 };

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 720 of file app_meetme.c.

00720                    {
00721    CONF_HASJOIN,
00722    CONF_HASLEFT
00723 };

Enumerator:
ENTER 
LEAVE 

Definition at line 568 of file app_meetme.c.

00568                     {
00569    ENTER,
00570    LEAVE
00571 };

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

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

00915                     {
00916    /*! A station has put the call on hold */
00917    SLA_EVENT_HOLD,
00918    /*! The state of a dial has changed */
00919    SLA_EVENT_DIAL_STATE,
00920    /*! The state of a ringing trunk has changed */
00921    SLA_EVENT_RINGING_TRUNK,
00922    /*! A reload of configuration has been requested */
00923    SLA_EVENT_RELOAD,
00924    /*! Poke the SLA thread so it can check if it can perform a reload */
00925    SLA_EVENT_CHECK_RELOAD,
00926 };

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

00825                      {
00826    /*! This means that any station can put it on hold, and any station
00827     * can retrieve the call from hold. */
00828    SLA_HOLD_OPEN,
00829    /*! This means that only the station that put the call on hold may
00830     * retrieve it from hold. */
00831    SLA_HOLD_PRIVATE,
00832 };

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

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

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 812 of file app_meetme.c.

00812                           {
00813    ALL_TRUNK_REFS,
00814    INACTIVE_TRUNK_REFS,
00815 };

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 563 of file app_meetme.c.

00563                    {
00564    VOL_UP,
00565    VOL_DOWN
00566 };


Function Documentation

static void __fini_sla_stations ( void   )  [static]

Definition at line 909 of file app_meetme.c.

00915 {

static void __fini_sla_trunks ( void   )  [static]

Definition at line 910 of file app_meetme.c.

00915 {

static void __init_sla_stations ( void   )  [static]

Definition at line 909 of file app_meetme.c.

00915 {

static void __init_sla_trunks ( void   )  [static]

Definition at line 910 of file app_meetme.c.

00915 {

static void __reg_module ( void   )  [static]

Definition at line 7388 of file app_meetme.c.

static void __unreg_module ( void   )  [static]

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

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

07063 {
07064    struct ast_conference *conf;
07065    char *parse;
07066    int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
07067    AST_DECLARE_APP_ARGS(args,
07068       AST_APP_ARG(keyword);
07069       AST_APP_ARG(confno);
07070    );
07071 
07072    if (ast_strlen_zero(data)) {
07073       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
07074       return -1;
07075    }
07076 
07077    parse = ast_strdupa(data);
07078    AST_STANDARD_APP_ARGS(args, parse);
07079 
07080    if (ast_strlen_zero(args.keyword)) {
07081       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
07082       return -1;
07083    }
07084 
07085    if (ast_strlen_zero(args.confno)) {
07086       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
07087       return -1;
07088    }
07089 
07090    AST_LIST_LOCK(&confs);
07091    AST_LIST_TRAVERSE(&confs, conf, list) {
07092       if (!strcmp(args.confno, conf->confno)) {
07093          result = acf_meetme_info_eval(args.keyword, conf);
07094          break;
07095       }
07096    }
07097    AST_LIST_UNLOCK(&confs);
07098 
07099    if (result > -1) {
07100       snprintf(buf, len, "%d", result);
07101    } else if (result == -1) {
07102       ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
07103       snprintf(buf, len, "0");
07104    } else if (result == -2) {
07105       ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno); 
07106       snprintf(buf, len, "0");
07107    }
07108 
07109    return 0;
07110 }

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

Definition at line 7044 of file app_meetme.c.

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

Referenced by acf_meetme_info().

07045 {
07046    if (!strcasecmp("lock", keyword)) {
07047       return conf->locked;
07048    } else if (!strcasecmp("parties", keyword)) {
07049       return conf->users;
07050    } else if (!strcasecmp("activity", keyword)) {
07051       time_t now;
07052       now = time(NULL);
07053       return (now - conf->start);
07054    } else if (!strcasecmp("dynamic", keyword)) {
07055       return conf->isdynamic;
07056    } else {
07057       return -1;
07058    }
07059 
07060 }

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

Definition at line 4913 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_channel_name(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag64, astman_append(), astman_get_header(), astman_send_error(), astman_send_listack(), ast_channel::caller, ast_conf_user::chan, CONFFLAG_ADMIN, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_conference::confno, ast_channel::connected, ast_party_connected_line::id, ast_party_caller::id, ast_party_id::name, ast_party_id::number, S_COR, ast_party_name::str, ast_party_number::str, ast_conf_user::talking, total, ast_conf_user::user_no, ast_conference::usercontainer, ast_conf_user::userflags, ast_party_name::valid, and ast_party_number::valid.

Referenced by load_module().

04914 {
04915    const char *actionid = astman_get_header(m, "ActionID");
04916    const char *conference = astman_get_header(m, "Conference");
04917    char idText[80] = "";
04918    struct ast_conference *cnf;
04919    struct ast_conf_user *user;
04920    struct ao2_iterator user_iter;
04921    int total = 0;
04922 
04923    if (!ast_strlen_zero(actionid))
04924       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04925 
04926    if (AST_LIST_EMPTY(&confs)) {
04927       astman_send_error(s, m, "No active conferences.");
04928       return 0;
04929    }
04930 
04931    astman_send_listack(s, m, "Meetme user list will follow", "start");
04932 
04933    /* Find the right conference */
04934    AST_LIST_LOCK(&confs);
04935    AST_LIST_TRAVERSE(&confs, cnf, list) {
04936       /* If we ask for one particular, and this isn't it, skip it */
04937       if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
04938          continue;
04939 
04940       /* Show all the users */
04941       user_iter = ao2_iterator_init(cnf->usercontainer, 0);
04942       while ((user = ao2_iterator_next(&user_iter))) {
04943          total++;
04944          astman_append(s,
04945             "Event: MeetmeList\r\n"
04946             "%s"
04947             "Conference: %s\r\n"
04948             "UserNumber: %d\r\n"
04949             "CallerIDNum: %s\r\n"
04950             "CallerIDName: %s\r\n"
04951             "ConnectedLineNum: %s\r\n"
04952             "ConnectedLineName: %s\r\n"
04953             "Channel: %s\r\n"
04954             "Admin: %s\r\n"
04955             "Role: %s\r\n"
04956             "MarkedUser: %s\r\n"
04957             "Muted: %s\r\n"
04958             "Talking: %s\r\n"
04959             "\r\n",
04960             idText,
04961             cnf->confno,
04962             user->user_no,
04963             S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
04964             S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
04965             S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
04966             S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<no name>"),
04967             ast_channel_name(user->chan),
04968             ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
04969             ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
04970             ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
04971             user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
04972             user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
04973          ao2_ref(user, -1);
04974       }
04975       ao2_iterator_destroy(&user_iter);
04976    }
04977    AST_LIST_UNLOCK(&confs);
04978    /* Send final confirmation */
04979    astman_append(s,
04980    "Event: MeetmeListComplete\r\n"
04981    "EventList: Complete\r\n"
04982    "ListItems: %d\r\n"
04983    "%s"
04984    "\r\n", total, idText);
04985    return 0;
04986 }

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

Definition at line 4988 of file app_meetme.c.

References 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_conference::confno, ast_conference::isdynamic, ast_conference::list, ast_conference::locked, ast_conference::markedusers, ast_conference::start, and ast_conference::users.

Referenced by load_module().

04989 {
04990    const char *actionid = astman_get_header(m, "ActionID");
04991    char idText[80] = "";
04992    struct ast_conference *cnf;
04993    int totalitems = 0;
04994    int hr, min, sec;
04995    time_t now;
04996    char markedusers[5];
04997 
04998    if (!ast_strlen_zero(actionid)) {
04999       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
05000    }
05001 
05002    if (AST_LIST_EMPTY(&confs)) {
05003       astman_send_error(s, m, "No active conferences.");
05004       return 0;
05005    }
05006 
05007    astman_send_listack(s, m, "Meetme conferences will follow", "start");
05008 
05009    now = time(NULL);
05010 
05011    /* Traverse the conference list */
05012    AST_LIST_LOCK(&confs);
05013    AST_LIST_TRAVERSE(&confs, cnf, list) {
05014       totalitems++;
05015 
05016       if (cnf->markedusers == 0) {
05017          strcpy(markedusers, "N/A");
05018       } else {
05019          sprintf(markedusers, "%.4d", cnf->markedusers);
05020       }
05021       hr = (now - cnf->start) / 3600;
05022       min = ((now - cnf->start) % 3600) / 60;
05023       sec = (now - cnf->start) % 60;
05024 
05025       astman_append(s,
05026       "Event: MeetmeListRooms\r\n"
05027       "%s"
05028       "Conference: %s\r\n"
05029       "Parties: %d\r\n"
05030       "Marked: %s\r\n"
05031       "Activity: %2.2d:%2.2d:%2.2d\r\n"
05032       "Creation: %s\r\n"
05033       "Locked: %s\r\n"
05034       "\r\n",
05035       idText,
05036       cnf->confno,
05037       cnf->users,
05038       markedusers,
05039       hr,  min, sec,
05040       cnf->isdynamic ? "Dynamic" : "Static",
05041       cnf->locked ? "Yes" : "No"); 
05042    }
05043    AST_LIST_UNLOCK(&confs);
05044 
05045    /* Send final confirmation */
05046    astman_append(s,
05047    "Event: MeetmeListRoomsComplete\r\n"
05048    "EventList: Complete\r\n"
05049    "ListItems: %d\r\n"
05050    "%s"
05051    "\r\n", totalitems, idText);
05052    return 0;
05053 }

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

Definition at line 4903 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04904 {
04905    return meetmemute(s, m, 1);
04906 }

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

Definition at line 4908 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04909 {
04910    return meetmemute(s, m, 0);
04911 }

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

The MeetMeadmin application.

MeetMeAdmin(confno, command, caller)

Definition at line 4641 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ao2_callback, ao2_find, ao2_ref, args, AST_APP_ARG, ast_atomic_fetchadd_int(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag64, CONFFLAG_ADMIN, ast_conference::confno, dispose_conf(), find_user(), ast_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().

04641                                                                   {
04642    char *params;
04643    struct ast_conference *cnf;
04644    struct ast_conf_user *user = NULL;
04645    AST_DECLARE_APP_ARGS(args,
04646       AST_APP_ARG(confno);
04647       AST_APP_ARG(command);
04648       AST_APP_ARG(user);
04649    );
04650    int res = 0;
04651 
04652    if (ast_strlen_zero(data)) {
04653       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
04654       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04655       return -1;
04656    }
04657 
04658    params = ast_strdupa(data);
04659    AST_STANDARD_APP_ARGS(args, params);
04660 
04661    if (!args.command) {
04662       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
04663       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04664       return -1;
04665    }
04666 
04667    AST_LIST_LOCK(&confs);
04668    AST_LIST_TRAVERSE(&confs, cnf, list) {
04669       if (!strcmp(cnf->confno, args.confno))
04670          break;
04671    }
04672 
04673    if (!cnf) {
04674       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
04675       AST_LIST_UNLOCK(&confs);
04676       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
04677       return 0;
04678    }
04679 
04680    ast_atomic_fetchadd_int(&cnf->refcount, 1);
04681 
04682    if (args.user) {
04683       user = find_user(cnf, args.user);
04684       if (!user) {
04685          ast_log(LOG_NOTICE, "Specified User not found!\n");
04686          res = -2;
04687          goto usernotfound;
04688       }
04689    }
04690 
04691    switch (*args.command) {
04692    case 76: /* L: Lock */ 
04693       cnf->locked = 1;
04694       break;
04695    case 108: /* l: Unlock */ 
04696       cnf->locked = 0;
04697       break;
04698    case 75: /* K: kick all users */
04699       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_kickme_cb, NULL);
04700       break;
04701    case 101: /* e: Eject last user*/
04702    {
04703       int max_no = 0;
04704       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
04705       user = ao2_find(cnf->usercontainer, &max_no, 0);
04706       if (!ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))
04707          user->adminflags |= ADMINFLAG_KICKME;
04708       else {
04709          res = -1;
04710          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
04711       }
04712       ao2_ref(user, -1);
04713       break;
04714    }
04715    case 77: /* M: Mute */ 
04716       user->adminflags |= ADMINFLAG_MUTED;
04717       break;
04718    case 78: /* N: Mute all (non-admin) users */
04719       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_muted_cb, NULL);
04720       break;               
04721    case 109: /* m: Unmute */ 
04722       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04723       break;
04724    case 110: /* n: Unmute all users */
04725       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, NULL);
04726       break;
04727    case 107: /* k: Kick user */ 
04728       user->adminflags |= ADMINFLAG_KICKME;
04729       break;
04730    case 118: /* v: Lower all users listen volume */
04731       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_voldown_cb, NULL);
04732       break;
04733    case 86: /* V: Raise all users listen volume */
04734       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_volup_cb, NULL);
04735       break;
04736    case 115: /* s: Lower all users speaking volume */
04737       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_voldown_cb, NULL);
04738       break;
04739    case 83: /* S: Raise all users speaking volume */
04740       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_volup_cb, NULL);
04741       break;
04742    case 82: /* R: Reset all volume levels */
04743       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_reset_vol_cb, NULL);
04744       break;
04745    case 114: /* r: Reset user's volume level */
04746       reset_volumes(user);
04747       break;
04748    case 85: /* U: Raise user's listen volume */
04749       tweak_listen_volume(user, VOL_UP);
04750       break;
04751    case 117: /* u: Lower user's listen volume */
04752       tweak_listen_volume(user, VOL_DOWN);
04753       break;
04754    case 84: /* T: Raise user's talk volume */
04755       tweak_talk_volume(user, VOL_UP);
04756       break;
04757    case 116: /* t: Lower user's talk volume */
04758       tweak_talk_volume(user, VOL_DOWN);
04759       break;
04760    case 'E': /* E: Extend conference */
04761       if (rt_extend_conf(args.confno)) {
04762          res = -1;
04763       }
04764       break;
04765    }
04766 
04767    if (args.user) {
04768       /* decrement reference from find_user */
04769       ao2_ref(user, -1);
04770    }
04771 usernotfound:
04772    AST_LIST_UNLOCK(&confs);
04773 
04774    dispose_conf(cnf);
04775    pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
04776 
04777    return 0;
04778 }

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

Definition at line 2114 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_debug, 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_mutex_lock, ast_mutex_unlock, ast_streamfile(), ast_waitstream(), CONF_HASLEFT, announce_listitem::confchan, announce_listitem::confusers, get_announce_filename(), announce_listitem::language, announce_listitem::namerecloc, and announce_listitem::vmrec.

Referenced by conf_run().

02115 {
02116    struct announce_listitem *current;
02117    struct ast_conference *conf = data;
02118    int res;
02119    char filename[PATH_MAX] = "";
02120    AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
02121    AST_LIST_HEAD_INIT_NOLOCK(&local_list);
02122 
02123    while (!conf->announcethread_stop) {
02124       ast_mutex_lock(&conf->announcelistlock);
02125       if (conf->announcethread_stop) {
02126          ast_mutex_unlock(&conf->announcelistlock);
02127          break;
02128       }
02129       if (AST_LIST_EMPTY(&conf->announcelist))
02130          ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
02131 
02132       AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
02133       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
02134 
02135       ast_mutex_unlock(&conf->announcelistlock);
02136       if (conf->announcethread_stop) {
02137          break;
02138       }
02139 
02140       for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
02141          ast_debug(1, "About to play %s\n", current->namerecloc);
02142          if (!ast_fileexists(current->namerecloc, NULL, NULL))
02143             continue;
02144          if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
02145             if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
02146                res = ast_waitstream(current->confchan, "");
02147             if (!res) {
02148                ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
02149                if (!ast_streamfile(current->confchan, filename, current->language))
02150                   ast_waitstream(current->confchan, "");
02151             }
02152          }
02153          if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
02154             /* only remove it if it isn't a VM recording file */
02155             ast_filedelete(current->namerecloc, NULL);
02156          }
02157       }
02158    }
02159 
02160    /* thread marked to stop, clean up */
02161    while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
02162       /* only delete if it's a vm rec */
02163       if (!current->vmrec) {
02164          ast_filedelete(current->namerecloc, NULL);
02165       }
02166       ao2_ref(current, -1);
02167    }
02168    return NULL;
02169 }

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

Definition at line 5363 of file app_meetme.c.

References ast_answer(), and ast_indicate().

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

05364 {
05365    ast_answer(chan);
05366    ast_indicate(chan, -1);
05367 }

AST_DATA_STRUCTURE ( ast_conf_user  ,
MEETME_USER_DATA_EXPORT   
)

AST_DATA_STRUCTURE ( ast_conference  ,
MEETME_DATA_EXPORT   
)

static struct ast_conference* build_conf ( const char *  confno,
const char *  pin,
const char *  pinadmin,
int  make,
int  dynamic,
int  refcount,
const struct ast_channel chan,
struct ast_test *  test 
) [static, read]

Find or create a conference.

Parameters:
confno The conference name/number
pin The regular user pin
pinadmin The admin pin
make Make the conf if it doesn't exist
dynamic Mark the newly created conference as dynamic
refcount How many references to mark on the conference
chan The asterisk channel
Returns:
A pointer to the conference struct, or NULL if it wasn't found and make or dynamic were not set.

Definition at line 1216 of file app_meetme.c.

References ast_conference::announcethread, ast_conference::announcethreadlock, ao2_container_alloc, ao2_ref, ast_atomic_fetchadd_int(), ast_calloc, ast_channel_uniqueid(), ast_copy_string(), ast_format_cap_add(), ast_format_cap_alloc_nolock(), ast_format_cap_destroy(), ast_format_set(), 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_by_id(), ast_set_write_format_by_id(), ast_test_status_update, ast_verb, ast_conference::chan, conf_map, ast_conference::confno, ast_conference::dahdiconf, ast_conference::fd, ast_channel::fds, ast_conference::isdynamic, ast_conference::listenlock, LOG_WARNING, ast_conference::maxusers, ast_conference::pin, ast_conference::pinadmin, ast_conference::playlock, ast_conference::recordthread, ast_conference::recordthreadlock, ast_conference::refcount, ast_conference::start, ast_conference::uniqueid, user_no_cmp(), and ast_conference::usercontainer.

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

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

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

Definition at line 2171 of file app_meetme.c.

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

Referenced by conf_run().

02172 {
02173    if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02174       return 1;
02175    }
02176 
02177    return (chan->_state == AST_STATE_UP);
02178 }

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

Definition at line 1026 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

01027 {
01028    int res;
01029    int x;
01030 
01031    while (len) {
01032       if (block) {
01033          x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
01034          res = ioctl(fd, DAHDI_IOMUX, &x);
01035       } else
01036          res = 0;
01037       if (res >= 0)
01038          res = write(fd, data, len);
01039       if (res < 1) {
01040          if (errno != EAGAIN) {
01041             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
01042             return -1;
01043          } else
01044             return 0;
01045       }
01046       len -= res;
01047       data += res;
01048    }
01049 
01050    return 0;
01051 }

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

The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command).

Definition at line 4782 of file app_meetme.c.

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

Referenced by load_module().

04782                                                                           {
04783    char *params;
04784    struct ast_conference *conf = NULL;
04785    struct ast_conf_user *user = NULL;
04786    AST_DECLARE_APP_ARGS(args,
04787       AST_APP_ARG(channel);
04788       AST_APP_ARG(command);
04789    );
04790 
04791    if (ast_strlen_zero(data)) {
04792       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
04793       return -1;
04794    }
04795    
04796    params = ast_strdupa(data);
04797    AST_STANDARD_APP_ARGS(args, params);
04798 
04799    if (!args.channel) {
04800       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
04801       return -1;
04802    }
04803 
04804    if (!args.command) {
04805       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
04806       return -1;
04807    }
04808 
04809    AST_LIST_LOCK(&confs);
04810    AST_LIST_TRAVERSE(&confs, conf, list) {
04811       if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
04812          break;
04813       }
04814    }
04815    
04816    if (!user) {
04817       ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
04818       AST_LIST_UNLOCK(&confs);
04819       return 0;
04820    }
04821    
04822    /* perform the specified action */
04823    switch (*args.command) {
04824       case 77: /* M: Mute */ 
04825          user->adminflags |= ADMINFLAG_MUTED;
04826          break;
04827       case 109: /* m: Unmute */ 
04828          user->adminflags &= ~ADMINFLAG_MUTED;
04829          break;
04830       case 107: /* k: Kick user */ 
04831          user->adminflags |= ADMINFLAG_KICKME;
04832          break;
04833       default: /* unknown command */
04834          ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
04835          break;
04836    }
04837    ao2_ref(user, -1);
04838    AST_LIST_UNLOCK(&confs);
04839    
04840    return 0;
04841 }

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

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

01331 {
01332    static const char * const cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
01333 
01334    int len = strlen(word);
01335    int which = 0;
01336    struct ast_conference *cnf = NULL;
01337    struct ast_conf_user *usr = NULL;
01338    char *confno = NULL;
01339    char usrno[50] = "";
01340    char *myline, *ret = NULL;
01341    
01342    if (pos == 1) {      /* Command */
01343       return ast_cli_complete(word, cmds, state);
01344    } else if (pos == 2) {  /* Conference Number */
01345       AST_LIST_LOCK(&confs);
01346       AST_LIST_TRAVERSE(&confs, cnf, list) {
01347          if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
01348             ret = cnf->confno;
01349             break;
01350          }
01351       }
01352       ret = ast_strdup(ret); /* dup before releasing the lock */
01353       AST_LIST_UNLOCK(&confs);
01354       return ret;
01355    } else if (pos == 3) {
01356       /* User Number || Conf Command option*/
01357       if (strstr(line, "mute") || strstr(line, "kick")) {
01358          if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
01359             return ast_strdup("all");
01360          which++;
01361          AST_LIST_LOCK(&confs);
01362 
01363          /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
01364          myline = ast_strdupa(line);
01365          if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
01366             while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
01367                ;
01368          }
01369          
01370          AST_LIST_TRAVERSE(&confs, cnf, list) {
01371             if (!strcmp(confno, cnf->confno))
01372                 break;
01373          }
01374 
01375          if (cnf) {
01376             struct ao2_iterator user_iter;
01377             user_iter = ao2_iterator_init(cnf->usercontainer, 0);
01378 
01379             while((usr = ao2_iterator_next(&user_iter))) {
01380                snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
01381                if (!strncasecmp(word, usrno, len) && ++which > state) {
01382                   ao2_ref(usr, -1);
01383                   break;
01384                }
01385                ao2_ref(usr, -1);
01386             }
01387             ao2_iterator_destroy(&user_iter);
01388             AST_LIST_UNLOCK(&confs);
01389             return usr ? ast_strdup(usrno) : NULL;
01390          }
01391          AST_LIST_UNLOCK(&confs);
01392       }
01393    }
01394 
01395    return NULL;
01396 }

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

The meetme() application.

Definition at line 4257 of file app_meetme.c.

References ast_channel::_state, ast_conference::adminopts, args, ARRAY_LEN, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options64(), ast_category_browse(), ast_channel_language(), ast_config_destroy(), ast_config_load, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime_multientry(), ast_log(), ast_say_digits(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag64, ast_variable_browse(), ast_variable_retrieve(), ast_verb, ast_waitstream(), conf_map, conf_run(), CONFFLAG_ADMIN, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFFLAG_QUIET, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), ast_conference::isdynamic, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, MAX_SETTINGS, 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.

04258 {
04259    int res = -1;
04260    char confno[MAX_CONFNUM] = "";
04261    int allowretry = 0;
04262    int retrycnt = 0;
04263    struct ast_conference *cnf = NULL;
04264    struct ast_flags64 confflags = {0};
04265    struct ast_flags config_flags = { 0 };
04266    int dynamic = 0;
04267    int empty = 0, empty_no_pin = 0;
04268    int always_prompt = 0;
04269    const char *notdata;
04270    char *info, the_pin[MAX_PIN] = "";
04271    AST_DECLARE_APP_ARGS(args,
04272       AST_APP_ARG(confno);
04273       AST_APP_ARG(options);
04274       AST_APP_ARG(pin);
04275    );
04276    char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
04277 
04278    if (ast_strlen_zero(data)) {
04279       allowretry = 1;
04280       notdata = "";
04281    } else {
04282       notdata = data;
04283    }
04284    
04285    if (chan->_state != AST_STATE_UP)
04286       ast_answer(chan);
04287 
04288    info = ast_strdupa(notdata);
04289 
04290    AST_STANDARD_APP_ARGS(args, info);  
04291 
04292    if (args.confno) {
04293       ast_copy_string(confno, args.confno, sizeof(confno));
04294       if (ast_strlen_zero(confno)) {
04295          allowretry = 1;
04296       }
04297    }
04298    
04299    if (args.pin)
04300       ast_copy_string(the_pin, args.pin, sizeof(the_pin));
04301 
04302    if (args.options) {
04303       ast_app_parse_options64(meetme_opts, &confflags, optargs, args.options);
04304       dynamic = ast_test_flag64(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
04305       if (ast_test_flag64(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
04306          strcpy(the_pin, "q");
04307 
04308       empty = ast_test_flag64(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
04309       empty_no_pin = ast_test_flag64(&confflags, CONFFLAG_EMPTYNOPIN);
04310       always_prompt = ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
04311    }
04312 
04313    do {
04314       if (retrycnt > 3)
04315          allowretry = 0;
04316       if (empty) {
04317          int i;
04318          struct ast_config *cfg;
04319          struct ast_variable *var;
04320          int confno_int;
04321 
04322          /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
04323          if ((empty_no_pin) || (!dynamic)) {
04324             cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
04325             if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
04326                var = ast_variable_browse(cfg, "rooms");
04327                while (var) {
04328                   char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
04329                   if (!strcasecmp(var->name, "conf")) {
04330                      int found = 0;
04331                      ast_copy_string(parse, var->value, sizeof(parse));
04332                      confno_tmp = strsep(&stringp, "|,");
04333                      if (!dynamic) {
04334                         /* For static:  run through the list and see if this conference is empty */
04335                         AST_LIST_LOCK(&confs);
04336                         AST_LIST_TRAVERSE(&confs, cnf, list) {
04337                            if (!strcmp(confno_tmp, cnf->confno)) {
04338                               /* The conference exists, therefore it's not empty */
04339                               found = 1;
04340                               break;
04341                            }
04342                         }
04343                         AST_LIST_UNLOCK(&confs);
04344                         if (!found) {
04345                            /* At this point, we have a confno_tmp (static conference) that is empty */
04346                            if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
04347                               /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
04348                                * Case 2:  empty_no_pin and pin is blank (but not NULL)
04349                                * Case 3:  not empty_no_pin
04350                                */
04351                               ast_copy_string(confno, confno_tmp, sizeof(confno));
04352                               break;
04353                            }
04354                         }
04355                      }
04356                   }
04357                   var = var->next;
04358                }
04359                ast_config_destroy(cfg);
04360             }
04361 
04362             if (ast_strlen_zero(confno) && (cfg = ast_load_realtime_multientry("meetme", "confno LIKE", "%", SENTINEL))) {
04363                const char *catg;
04364                for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
04365                   const char *confno_tmp = ast_variable_retrieve(cfg, catg, "confno");
04366                   const char *pin_tmp = ast_variable_retrieve(cfg, catg, "pin");
04367                   if (ast_strlen_zero(confno_tmp)) {
04368                      continue;
04369                   }
04370                   if (!dynamic) {
04371                      int found = 0;
04372                      /* For static:  run through the list and see if this conference is empty */
04373                      AST_LIST_LOCK(&confs);
04374                      AST_LIST_TRAVERSE(&confs, cnf, list) {
04375                         if (!strcmp(confno_tmp, cnf->confno)) {
04376                            /* The conference exists, therefore it's not empty */
04377                            found = 1;
04378                            break;
04379                         }
04380                      }
04381                      AST_LIST_UNLOCK(&confs);
04382                      if (!found) {
04383                         /* At this point, we have a confno_tmp (realtime conference) that is empty */
04384                         if ((empty_no_pin && ast_strlen_zero(pin_tmp)) || (!empty_no_pin)) {
04385                            /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
04386                             * Case 2:  empty_no_pin and pin is blank (but not NULL)
04387                             * Case 3:  not empty_no_pin
04388                             */
04389                            ast_copy_string(confno, confno_tmp, sizeof(confno));
04390                            break;
04391                         }
04392                      }
04393                   }
04394                }
04395                ast_config_destroy(cfg);
04396             }
04397          }
04398 
04399          /* Select first conference number not in use */
04400          if (ast_strlen_zero(confno) && dynamic) {
04401             AST_LIST_LOCK(&confs);
04402             for (i = 0; i < ARRAY_LEN(conf_map); i++) {
04403                if (!conf_map[i]) {
04404                   snprintf(confno, sizeof(confno), "%d", i);
04405                   conf_map[i] = 1;
04406                   break;
04407                }
04408             }
04409             AST_LIST_UNLOCK(&confs);
04410          }
04411 
04412          /* Not found? */
04413          if (ast_strlen_zero(confno)) {
04414             res = ast_streamfile(chan, "conf-noempty", ast_channel_language(chan));
04415             if (!res)
04416                ast_waitstream(chan, "");
04417          } else {
04418             if (sscanf(confno, "%30d", &confno_int) == 1) {
04419                if (!ast_test_flag64(&confflags, CONFFLAG_QUIET)) {
04420                   res = ast_streamfile(chan, "conf-enteringno", ast_channel_language(chan));
04421                   if (!res) {
04422                      ast_waitstream(chan, "");
04423                      res = ast_say_digits(chan, confno_int, "", ast_channel_language(chan));
04424                   }
04425                }
04426             } else {
04427                ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
04428             }
04429          }
04430       }
04431 
04432       while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
04433          /* Prompt user for conference number */
04434          res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
04435          if (res < 0) {
04436             /* Don't try to validate when we catch an error */
04437             confno[0] = '\0';
04438             allowretry = 0;
04439             break;
04440          }
04441       }
04442       if (!ast_strlen_zero(confno)) {
04443          /* Check the validity of the conference */
04444          cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
04445             sizeof(the_pin), 1, &confflags);
04446          if (!cnf) {
04447             int too_early = 0;
04448 
04449             cnf = find_conf_realtime(chan, confno, 1, dynamic, 
04450                the_pin, sizeof(the_pin), 1, &confflags, &too_early, optargs);
04451             if (rt_schedule && too_early)
04452                allowretry = 0;
04453          }
04454 
04455          if (!cnf) {
04456             if (allowretry) {
04457                confno[0] = '\0';
04458                res = ast_streamfile(chan, "conf-invalid", ast_channel_language(chan));
04459                if (!res)
04460                   ast_waitstream(chan, "");
04461                res = -1;
04462             }
04463          } else {
04464             /* Conference requires a pin for specified access level */
04465             int req_pin = !ast_strlen_zero(cnf->pin) ||
04466                (!ast_strlen_zero(cnf->pinadmin) &&
04467                   ast_test_flag64(&confflags, CONFFLAG_ADMIN));
04468             /* The following logic was derived from a
04469              * 4 variable truth table and defines which
04470              * circumstances are not exempt from pin
04471              * checking.
04472              * If this needs to be modified, write the
04473              * truth table back out from the boolean
04474              * expression AB+A'D+C', change the erroneous
04475              * result, and rederive the expression.
04476              * Variables:
04477              *  A: pin provided?
04478              *  B: always prompt?
04479              *  C: dynamic?
04480              *  D: has users? */
04481             int not_exempt = !cnf->isdynamic;
04482             not_exempt = not_exempt || (!ast_strlen_zero(args.pin) && ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT));
04483             not_exempt = not_exempt || (ast_strlen_zero(args.pin) && cnf->users);
04484             if (req_pin && not_exempt) {
04485                char pin[MAX_PIN] = "";
04486                int j;
04487 
04488                /* Allow the pin to be retried up to 3 times */
04489                for (j = 0; j < 3; j++) {
04490                   if (*the_pin && (always_prompt == 0)) {
04491                      ast_copy_string(pin, the_pin, sizeof(pin));
04492                      res = 0;
04493                   } else {
04494                      /* Prompt user for pin if pin is required */
04495                      res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
04496                   }
04497                   if (res >= 0) {
04498                      if ((!strcasecmp(pin, cnf->pin) &&
04499                           (ast_strlen_zero(cnf->pinadmin) ||
04500                            !ast_test_flag64(&confflags, CONFFLAG_ADMIN))) ||
04501                           (!ast_strlen_zero(cnf->pinadmin) &&
04502                            !strcasecmp(pin, cnf->pinadmin))) {
04503                         /* Pin correct */
04504                         allowretry = 0;
04505                         if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
04506                            if (!ast_strlen_zero(cnf->adminopts)) {
04507                               char *opts = ast_strdupa(cnf->adminopts);
04508                               ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
04509                            }
04510                         } else {
04511                            if (!ast_strlen_zero(cnf->useropts)) {
04512                               char *opts = ast_strdupa(cnf->useropts);
04513                               ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
04514                            }
04515                         }
04516                         /* Run the conference */
04517                         ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
04518                         res = conf_run(chan, cnf, &confflags, optargs);
04519                         break;
04520                      } else {
04521                         /* Pin invalid */
04522                         if (!ast_streamfile(chan, "conf-invalidpin", ast_channel_language(chan))) {
04523                            res = ast_waitstream(chan, AST_DIGIT_ANY);
04524                            ast_stopstream(chan);
04525                         } else {
04526                            ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
04527                            break;
04528                         }
04529                         if (res < 0)
04530                            break;
04531                         pin[0] = res;
04532                         pin[1] = '\0';
04533                         res = -1;
04534                         if (allowretry)
04535                            confno[0] = '\0';
04536                      }
04537                   } else {
04538                      /* failed when getting the pin */
04539                      res = -1;
04540                      allowretry = 0;
04541                      /* see if we need to get rid of the conference */
04542                      break;
04543                   }
04544 
04545                   /* Don't retry pin with a static pin */
04546                   if (*the_pin && (always_prompt == 0)) {
04547                      break;
04548                   }
04549                }
04550             } else {
04551                /* No pin required */
04552                allowretry = 0;
04553 
04554                /* For RealTime conferences without a pin 
04555                 * should still support loading options
04556                 */
04557                if (!ast_strlen_zero(cnf->useropts)) {
04558                   char *opts = ast_strdupa(cnf->useropts);
04559                   ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
04560                }
04561 
04562                /* Run the conference */
04563                res = conf_run(chan, cnf, &confflags, optargs);
04564             }
04565             dispose_conf(cnf);
04566             cnf = NULL;
04567          }
04568       }
04569    } while (allowretry);
04570 
04571    if (cnf)
04572       dispose_conf(cnf);
04573    
04574    return res;
04575 }

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

Definition at line 1810 of file app_meetme.c.

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

Referenced by conf_run().

01811 {
01812    int x;
01813 
01814    /* read any frames that may be waiting on the channel
01815       and throw them away
01816    */
01817    if (chan) {
01818       struct ast_frame *f;
01819 
01820       /* when no frames are available, this will wait
01821          for 1 millisecond maximum
01822       */
01823       while (ast_waitfor(chan, 1)) {
01824          f = ast_read(chan);
01825          if (f)
01826             ast_frfree(f);
01827          else /* channel was hung up or something else happened */
01828             break;
01829       }
01830    }
01831 
01832    /* flush any data sitting in the pseudo channel */
01833    x = DAHDI_FLUSH_ALL;
01834    if (ioctl(fd, DAHDI_FLUSH, &x))
01835       ast_log(LOG_WARNING, "Error flushing channel\n");
01836 
01837 }

static int conf_free ( struct ast_conference conf  )  [static]

Remove the conference from the list and free it.

We assume that this was called while holding conflock.

Definition at line 1842 of file app_meetme.c.

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

Referenced by dispose_conf().

01843 {
01844    int x;
01845    struct announce_listitem *item;
01846    
01847    AST_LIST_REMOVE(&confs, conf, list);
01848    manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01849 
01850    if (conf->recording == MEETME_RECORD_ACTIVE) {
01851       conf->recording = MEETME_RECORD_TERMINATE;
01852       AST_LIST_UNLOCK(&confs);
01853       while (1) {
01854          usleep(1);
01855          AST_LIST_LOCK(&confs);
01856          if (conf->recording == MEETME_RECORD_OFF)
01857             break;
01858          AST_LIST_UNLOCK(&confs);
01859       }
01860    }
01861 
01862    for (x = 0; x < AST_FRAME_BITS; x++) {
01863       if (conf->transframe[x])
01864          ast_frfree(conf->transframe[x]);
01865       if (conf->transpath[x])
01866          ast_translator_free_path(conf->transpath[x]);
01867    }
01868    if (conf->announcethread != AST_PTHREADT_NULL) {
01869       ast_mutex_lock(&conf->announcelistlock);
01870       conf->announcethread_stop = 1;
01871       ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01872       ast_cond_signal(&conf->announcelist_addition);
01873       ast_mutex_unlock(&conf->announcelistlock);
01874       pthread_join(conf->announcethread, NULL);
01875    
01876       while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01877          /* If it's a voicemail greeting file we don't want to remove it */
01878          if (!item->vmrec){
01879             ast_filedelete(item->namerecloc, NULL);
01880          }
01881          ao2_ref(item, -1);
01882       }
01883       ast_mutex_destroy(&conf->announcelistlock);
01884    }
01885 
01886    if (conf->origframe)
01887       ast_frfree(conf->origframe);
01888    if (conf->lchan)
01889       ast_hangup(conf->lchan);
01890    if (conf->chan)
01891       ast_hangup(conf->chan);
01892    if (conf->fd >= 0)
01893       close(conf->fd);
01894    if (conf->recordingfilename) {
01895       ast_free(conf->recordingfilename);
01896    }
01897    if (conf->usercontainer) {
01898       ao2_ref(conf->usercontainer, -1);
01899    }
01900    if (conf->recordingformat) {
01901       ast_free(conf->recordingformat);
01902    }
01903    ast_mutex_destroy(&conf->playlock);
01904    ast_mutex_destroy(&conf->listenlock);
01905    ast_mutex_destroy(&conf->recordthreadlock);
01906    ast_mutex_destroy(&conf->announcethreadlock);
01907    ast_free(conf);
01908 
01909    return 0;
01910 }

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

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

01145 {
01146    unsigned char *data;
01147    int len;
01148    int res = -1;
01149 
01150    if (!ast_check_hangup(chan))
01151       res = ast_autoservice_start(chan);
01152 
01153    AST_LIST_LOCK(&confs);
01154 
01155    switch(sound) {
01156    case ENTER:
01157       data = enter;
01158       len = sizeof(enter);
01159       break;
01160    case LEAVE:
01161       data = leave;
01162       len = sizeof(leave);
01163       break;
01164    default:
01165       data = NULL;
01166       len = 0;
01167    }
01168    if (data) {
01169       careful_write(conf->fd, data, len, 1);
01170    }
01171 
01172    AST_LIST_UNLOCK(&confs);
01173 
01174    if (!res) 
01175       ast_autoservice_stop(chan);
01176 }

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

Definition at line 1912 of file app_meetme.c.

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

Referenced by conf_run().

01914 {
01915    struct ast_conf_user *user;
01916    struct ao2_iterator user_iter;
01917 
01918    user_iter = ao2_iterator_init(conf->usercontainer, 0);
01919    while ((user = ao2_iterator_next(&user_iter))) {
01920       if (user == sender) {
01921          ao2_ref(user, -1);
01922          continue;
01923       }
01924       if (ast_write(user->chan, f) < 0)
01925          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", ast_channel_name(user->chan));
01926       ao2_ref(user, -1);
01927    }
01928    ao2_iterator_destroy(&user_iter);
01929 }

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

Definition at line 2253 of file app_meetme.c.

References volume::actual, ADMINFLAG_HANGUP, 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_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_channel_language(), ast_channel_lock, ast_channel_name(), ast_channel_setoption(), ast_channel_uniqueid(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag64, 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_fileexists(), ast_format_cap_add(), ast_format_cap_alloc_nolock(), ast_format_cap_destroy(), ast_format_from_old_bitfield(), ast_format_set(), AST_FORMAT_SLINEAR, ast_format_to_old_bitfield(), ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_free, ast_frfree, AST_FRIENDLY_OFFSET, ast_func_write(), ast_goto_if_exists(), ast_hangup(), ast_indicate(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), ast_manager_event, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), ast_mktime(), ast_module_helper(), ast_moh_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_flag64, ast_set_read_format_by_id(), ast_set_write_format_by_id(), ast_stopstream(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_test_flag64, ast_translate(), ast_translator_build_path(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_update_realtime(), ast_variables_destroy(), ast_verb, ast_verbose, ast_waitfor_nandfds(), ast_waitstream(), ast_write(), ast_channel::audiohooks, ast_conference::bookid, ast_channel::caller, can_write(), careful_write(), ast_conference::chan, ast_conf_user::chan, 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_INTROMSG, CONFFLAG_INTROUSER, CONFFLAG_INTROUSER_VMREC, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_KEYEXIT, CONFFLAG_KICK_CONTINUE, CONFFLAG_KILL_LAST_MAN_STANDING, 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::connected, ast_channel::context, 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_subclass::format, ast_frame::frametype, ast_conference::gmuted, ast_format::id, ast_party_connected_line::id, ast_party_caller::id, ast_frame_subclass::integer, ast_conf_user::jointime, ast_conf_user::kicktime, announce_listitem::language, ast_conference::lchan, LEAVE, ast_conf_user::listen, ast_conference::listenlock, ast_conference::locked, LOG_WARNING, ast_channel::macrocontext, mailbox, ast_conference::markedusers, ast_conference::maxusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, MEETME_RECORD_ACTIVE, ast_channel::monitor, ast_variable::name, ast_party_id::name, announce_listitem::namerecloc, ast_conf_user::namerecloc, ast_variable::next, ast_party_id::number, OBJ_NODATA, ast_frame::offset, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_EXITKEYS, OPT_ARG_INTROMSG, OPT_ARG_INTROUSER_VMREC, 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_COR, ast_frame::samples, set_talk_volume(), set_user_talking(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_conf_user::start_time, ast_party_name::str, ast_party_number::str, 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, user_max_cmp(), ast_conf_user::user_no, user_set_hangup_cb(), user_set_kickme_cb(), user_set_muted_cb(), user_set_unmuted_cb(), ast_conference::usercontainer, ast_conf_user::userflags, ast_conference::users, ast_party_name::valid, ast_party_number::valid, ast_variable::value, var, announce_listitem::vmrec, VOL_DOWN, VOL_UP, ast_conf_user::warning_freq, and ast_conf_user::warning_sound.

02254 {
02255    struct ast_conf_user *user = NULL;
02256    int fd;
02257    struct dahdi_confinfo dahdic, dahdic_empty;
02258    struct ast_frame *f;
02259    struct ast_channel *c;
02260    struct ast_frame fr;
02261    int outfd;
02262    int ms;
02263    int nfds;
02264    int res;
02265    int retrydahdi;
02266    int origfd;
02267    int musiconhold = 0, mohtempstopped = 0;
02268    int firstpass = 0;
02269    int lastmarked = 0;
02270    int currentmarked = 0;
02271    int ret = -1;
02272    int x;
02273    int menu_active = 0;
02274    int menu8_active = 0;
02275    int talkreq_manager = 0;
02276    int using_pseudo = 0;
02277    int duration = 20;
02278    int sent_event = 0;
02279    int checked = 0;
02280    int announcement_played = 0;
02281    struct timeval now;
02282    struct ast_dsp *dsp = NULL;
02283    struct ast_app *agi_app;
02284    char *agifile, *mod_speex;
02285    const char *agifiledefault = "conf-background.agi", *tmpvar;
02286    char meetmesecs[30] = "";
02287    char exitcontext[AST_MAX_CONTEXT] = "";
02288    char recordingtmp[AST_MAX_EXTENSION] = "";
02289    char members[10] = "";
02290    int dtmf, opt_waitmarked_timeout = 0;
02291    time_t timeout = 0;
02292    struct dahdi_bufferinfo bi;
02293    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
02294    char *buf = __buf + AST_FRIENDLY_OFFSET;
02295    char *exitkeys = NULL;
02296    unsigned int calldurationlimit = 0;
02297    long timelimit = 0;
02298    long play_warning = 0;
02299    long warning_freq = 0;
02300    const char *warning_sound = NULL;
02301    const char *end_sound = NULL;
02302    char *parse;
02303    long time_left_ms = 0;
02304    struct timeval nexteventts = { 0, };
02305    int to;
02306    int setusercount = 0;
02307    int confsilence = 0, totalsilence = 0;
02308    char *mailbox, *context;
02309    struct ast_format_cap *cap_slin = ast_format_cap_alloc_nolock();
02310    struct ast_format tmpfmt;
02311 
02312    if (!cap_slin) {
02313       goto conf_run_cleanup;
02314    }
02315    ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
02316 
02317    if (!(user = ao2_alloc(sizeof(*user), NULL))) {
02318       goto conf_run_cleanup;
02319    }
02320 
02321    /* Possible timeout waiting for marked user */
02322    if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
02323       !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
02324       (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
02325       (opt_waitmarked_timeout > 0)) {
02326       timeout = time(NULL) + opt_waitmarked_timeout;
02327    }
02328 
02329    if (ast_test_flag64(confflags, CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
02330       calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
02331       ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
02332    }
02333 
02334    if (ast_test_flag64(confflags, CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
02335       char *limit_str, *warning_str, *warnfreq_str;
02336       const char *var;
02337 
02338       parse = optargs[OPT_ARG_DURATION_LIMIT];
02339       limit_str = strsep(&parse, ":");
02340       warning_str = strsep(&parse, ":");
02341       warnfreq_str = parse;
02342 
02343       timelimit = atol(limit_str);
02344       if (warning_str)
02345          play_warning = atol(warning_str);
02346       if (warnfreq_str)
02347          warning_freq = atol(warnfreq_str);
02348 
02349       if (!timelimit) {
02350          timelimit = play_warning = warning_freq = 0;
02351          warning_sound = NULL;
02352       } else if (play_warning > timelimit) {
02353          if (!warning_freq) {
02354             play_warning = 0;
02355          } else {
02356             while (play_warning > timelimit)
02357                play_warning -= warning_freq;
02358             if (play_warning < 1)
02359                play_warning = warning_freq = 0;
02360          }
02361       }
02362 
02363       ast_verb(3, "Setting conference duration limit to: %ldms.\n", timelimit);
02364       if (play_warning) {
02365          ast_verb(3, "Setting warning time to %ldms from the conference duration limit.\n", play_warning);
02366       }
02367       if (warning_freq) {
02368          ast_verb(3, "Setting warning frequency to %ldms.\n", warning_freq);
02369       }
02370 
02371       ast_channel_lock(chan);
02372       if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
02373          var = ast_strdupa(var);
02374       }
02375       ast_channel_unlock(chan);
02376 
02377       warning_sound = var ? var : "timeleft";
02378 
02379       ast_channel_lock(chan);
02380       if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
02381          var = ast_strdupa(var);
02382       }
02383       ast_channel_unlock(chan);
02384 
02385       end_sound = var ? var : NULL;
02386 
02387       /* undo effect of S(x) in case they are both used */
02388       calldurationlimit = 0;
02389       /* more efficient do it like S(x) does since no advanced opts */
02390       if (!play_warning && !end_sound && timelimit) {
02391          calldurationlimit = timelimit / 1000;
02392          timelimit = play_warning = warning_freq = 0;
02393       } else {
02394          ast_debug(2, "Limit Data for this call:\n");
02395          ast_debug(2, "- timelimit     = %ld\n", timelimit);
02396          ast_debug(2, "- play_warning  = %ld\n", play_warning);
02397          ast_debug(2, "- warning_freq  = %ld\n", warning_freq);
02398          ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
02399          ast_debug(2, "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
02400       }
02401    }
02402 
02403    /* Get exit keys */
02404    if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
02405       if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
02406          exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
02407       else
02408          exitkeys = ast_strdupa("#"); /* Default */
02409    }
02410    
02411    if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
02412       if (!conf->recordingfilename) {
02413          const char *var;
02414          ast_channel_lock(chan);
02415          if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
02416             conf->recordingfilename = ast_strdup(var);
02417          }
02418          if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
02419             conf->recordingformat = ast_strdup(var);
02420          }
02421          ast_channel_unlock(chan);
02422          if (!conf->recordingfilename) {
02423             snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
02424             conf->recordingfilename = ast_strdup(recordingtmp);
02425          }
02426          if (!conf->recordingformat) {
02427             conf->recordingformat = ast_strdup("wav");
02428          }
02429          ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
02430                 conf->confno, conf->recordingfilename, conf->recordingformat);
02431       }
02432    }
02433 
02434    ast_mutex_lock(&conf->recordthreadlock);
02435    if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
02436       ((conf->lchan = ast_request("DAHDI", cap_slin, chan, "pseudo", NULL)))) {
02437       ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
02438       ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
02439       dahdic.chan = 0;
02440       dahdic.confno = conf->dahdiconf;
02441       dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
02442       if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
02443          ast_log(LOG_WARNING, "Error starting listen channel\n");
02444          ast_hangup(conf->lchan);
02445          conf->lchan = NULL;
02446       } else {
02447          ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
02448       }
02449    }
02450    ast_mutex_unlock(&conf->recordthreadlock);
02451 
02452    ast_mutex_lock(&conf->announcethreadlock);
02453    if ((conf->announcethread == AST_PTHREADT_NULL) && !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
02454       ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC)) {
02455       ast_mutex_init(&conf->announcelistlock);
02456       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
02457       ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
02458    }
02459    ast_mutex_unlock(&conf->announcethreadlock);
02460 
02461    time(&user->jointime);
02462    
02463    user->timelimit = timelimit;
02464    user->play_warning = play_warning;
02465    user->warning_freq = warning_freq;
02466    user->warning_sound = warning_sound;
02467    user->end_sound = end_sound;  
02468    
02469    if (calldurationlimit > 0) {
02470       time(&user->kicktime);
02471       user->kicktime = user->kicktime + calldurationlimit;
02472    }
02473    
02474    if (ast_tvzero(user->start_time))
02475       user->start_time = ast_tvnow();
02476    time_left_ms = user->timelimit;
02477    
02478    if (user->timelimit) {
02479       nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
02480       nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
02481    }
02482 
02483    if (conf->locked && (!ast_test_flag64(confflags, CONFFLAG_ADMIN))) {
02484       /* Sorry, but this conference is locked! */  
02485       if (!ast_streamfile(chan, "conf-locked", ast_channel_language(chan)))
02486          ast_waitstream(chan, "");
02487       goto outrun;
02488    }
02489 
02490       ast_mutex_lock(&conf->playlock);
02491 
02492    if (rt_schedule && conf->maxusers) {
02493       if (conf->users >= conf->maxusers) {
02494          /* Sorry, but this confernce has reached the participant limit! */   
02495          if (!ast_streamfile(chan, "conf-full", ast_channel_language(chan)))
02496             ast_waitstream(chan, "");
02497          ast_mutex_unlock(&conf->playlock);
02498          goto outrun;
02499       }
02500    }
02501 
02502    ao2_lock(conf->usercontainer);
02503    ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &user->user_no);
02504    user->user_no++;
02505    ao2_link(conf->usercontainer, user);
02506    ao2_unlock(conf->usercontainer);
02507 
02508    user->chan = chan;
02509    user->userflags = *confflags;
02510    user->adminflags = ast_test_flag64(confflags, CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
02511    user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
02512    user->talking = -1;
02513 
02514    ast_mutex_unlock(&conf->playlock);
02515 
02516    if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC))) {
02517       char destdir[PATH_MAX];
02518 
02519       snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
02520 
02521       if (ast_mkdir(destdir, 0777) != 0) {
02522          ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
02523          goto outrun;
02524       }
02525 
02526       if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
02527          context = ast_strdupa(optargs[OPT_ARG_INTROUSER_VMREC]);
02528          mailbox = strsep(&context, "@");
02529 
02530          if (ast_strlen_zero(mailbox)) {
02531             /* invalid input, clear the v flag*/
02532             ast_clear_flag64(confflags,CONFFLAG_INTROUSER_VMREC);
02533             ast_log(LOG_WARNING,"You must specify a mailbox in the v() option\n");
02534          } else {
02535             if (ast_strlen_zero(context)) {
02536                 context = "default";
02537             }
02538             /* if there is no mailbox we don't need to do this logic  */
02539             snprintf(user->namerecloc, sizeof(user->namerecloc),
02540                 "%s/voicemail/%s/%s/greet",ast_config_AST_SPOOL_DIR,context,mailbox);
02541 
02542             /* if the greeting doesn't exist then use the temp file method instead, clear flag v */
02543             if (!ast_fileexists(user->namerecloc, NULL, NULL)){
02544                snprintf(user->namerecloc, sizeof(user->namerecloc),
02545                    "%s/meetme-username-%s-%d", destdir,
02546                    conf->confno, user->user_no);
02547                ast_clear_flag64(confflags, CONFFLAG_INTROUSER_VMREC);
02548             }
02549          }
02550       } else {
02551          snprintf(user->namerecloc, sizeof(user->namerecloc),
02552              "%s/meetme-username-%s-%d", destdir,
02553              conf->confno, user->user_no);
02554       }
02555 
02556       res = 0;
02557       if (ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) && !ast_fileexists(user->namerecloc, NULL, NULL))
02558          res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
02559       else if (ast_test_flag64(confflags, CONFFLAG_INTROUSER) && !ast_fileexists(user->namerecloc, NULL, NULL))
02560          res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
02561       if (res == -1)
02562          goto outrun;
02563 
02564    }
02565 
02566    ast_mutex_lock(&conf->playlock);
02567 
02568    if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER))
02569       conf->markedusers++;
02570    conf->users++;
02571    if (rt_log_members) {
02572       /* Update table */
02573       snprintf(members, sizeof(members), "%d", conf->users);
02574       ast_realtime_require_field("meetme",
02575          "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
02576          "members", RQ_UINTEGER1, strlen(members),
02577          NULL);
02578       ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
02579    }
02580    setusercount = 1;
02581 
02582    /* This device changed state now - if this is the first user */
02583    if (conf->users == 1)
02584       ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
02585 
02586    ast_mutex_unlock(&conf->playlock);
02587 
02588    /* return the unique ID of the conference */
02589    pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
02590 
02591    if (ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT)) {
02592       ast_channel_lock(chan);
02593       if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
02594          ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
02595       } else if (!ast_strlen_zero(chan->macrocontext)) {
02596          ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
02597       } else {
02598          ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
02599       }
02600       ast_channel_unlock(chan);
02601    }
02602 
02603    /* Play an arbitrary intro message */
02604    if (ast_test_flag64(confflags, CONFFLAG_INTROMSG) &&
02605          !ast_strlen_zero(optargs[OPT_ARG_INTROMSG])) {
02606       if (!ast_streamfile(chan, optargs[OPT_ARG_INTROMSG], ast_channel_language(chan))) {
02607          ast_waitstream(chan, "");
02608       }
02609    }
02610 
02611    if (!ast_test_flag64(confflags, (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
02612       if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED))
02613          if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan)))
02614             ast_waitstream(chan, "");
02615       if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && conf->markedusers == 0)
02616          if (!ast_streamfile(chan, "conf-waitforleader", ast_channel_language(chan)))
02617             ast_waitstream(chan, "");
02618    }
02619 
02620    if (ast_test_flag64(confflags, CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
02621       int keepplaying = 1;
02622 
02623       if (conf->users == 2) { 
02624          if (!ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
02625             res = ast_waitstream(chan, AST_DIGIT_ANY);
02626             ast_stopstream(chan);
02627             if (res > 0)
02628                keepplaying = 0;
02629             else if (res == -1)
02630                goto outrun;
02631          }
02632       } else { 
02633          if (!ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
02634             res = ast_waitstream(chan, AST_DIGIT_ANY);
02635             ast_stopstream(chan);
02636             if (res > 0)
02637                keepplaying = 0;
02638             else if (res == -1)
02639                goto outrun;
02640          }
02641          if (keepplaying) {
02642             res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
02643             if (res > 0)
02644                keepplaying = 0;
02645             else if (res == -1)
02646                goto outrun;
02647          }
02648          if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
02649             res = ast_waitstream(chan, AST_DIGIT_ANY);
02650             ast_stopstream(chan);
02651             if (res > 0)
02652                keepplaying = 0;
02653             else if (res == -1) 
02654                goto outrun;
02655          }
02656       }
02657    }
02658 
02659    if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02660       /* We're leaving this alone until the state gets changed to up */
02661       ast_indicate(chan, -1);
02662    }
02663 
02664    if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
02665       ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", ast_channel_name(chan));
02666       goto outrun;
02667    }
02668 
02669    if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
02670       ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", ast_channel_name(chan));
02671       goto outrun;
02672    }
02673 
02674    /* Reduce background noise from each participant */
02675    if ((mod_speex = ast_module_helper("", "codec_speex", 0, 0, 0, 0))) {
02676       ast_free(mod_speex);
02677       ast_func_write(chan, "DENOISE(rx)", "on");
02678    }
02679 
02680    retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
02681    user->dahdichannel = !retrydahdi;
02682 
02683  dahdiretry:
02684    origfd = chan->fds[0];
02685    if (retrydahdi) {
02686       /* open pseudo in non-blocking mode */
02687       fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
02688       if (fd < 0) {
02689          ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
02690          goto outrun;
02691       }
02692       using_pseudo = 1;
02693       /* Setup buffering information */
02694       memset(&bi, 0, sizeof(bi));
02695       bi.bufsize = CONF_SIZE / 2;
02696       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
02697       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
02698       bi.numbufs = audio_buffers;
02699       if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
02700          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
02701          close(fd);
02702          goto outrun;
02703       }
02704       x = 1;
02705       if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
02706          ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
02707          close(fd);
02708          goto outrun;
02709       }
02710       nfds = 1;
02711    } else {
02712       /* XXX Make sure we're not running on a pseudo channel XXX */
02713       fd = chan->fds[0];
02714       nfds = 0;
02715    }
02716    memset(&dahdic, 0, sizeof(dahdic));
02717    memset(&dahdic_empty, 0, sizeof(dahdic_empty));
02718    /* Check to see if we're in a conference... */
02719    dahdic.chan = 0;
02720    if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
02721       ast_log(LOG_WARNING, "Error getting conference\n");
02722       close(fd);
02723       goto outrun;
02724    }
02725    if (dahdic.confmode) {
02726       /* Whoa, already in a conference...  Retry... */
02727       if (!retrydahdi) {
02728          ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
02729          retrydahdi = 1;
02730          goto dahdiretry;
02731       }
02732    }
02733    memset(&dahdic, 0, sizeof(dahdic));
02734    /* Add us to the conference */
02735    dahdic.chan = 0;
02736    dahdic.confno = conf->dahdiconf;
02737 
02738    if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
02739          ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) || ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)) && conf->users > 1) {
02740       struct announce_listitem *item;
02741       if (!(item = ao2_alloc(sizeof(*item), NULL)))
02742          goto outrun;
02743       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02744       ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
02745       item->confchan = conf->chan;
02746       item->confusers = conf->users;
02747       if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
02748          item->vmrec = 1;
02749       }
02750       item->announcetype = CONF_HASJOIN;
02751       ast_mutex_lock(&conf->announcelistlock);
02752       ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
02753       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02754       ast_cond_signal(&conf->announcelist_addition);
02755       ast_mutex_unlock(&conf->announcelistlock);
02756 
02757       while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
02758          ;
02759       }
02760       ao2_ref(item, -1);
02761    }
02762 
02763    if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && !conf->markedusers)
02764       dahdic.confmode = DAHDI_CONF_CONF;
02765    else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
02766       dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02767    else if (ast_test_flag64(confflags, CONFFLAG_TALKER))
02768       dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02769    else
02770       dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02771 
02772    if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02773       ast_log(LOG_WARNING, "Error setting conference\n");
02774       close(fd);
02775       goto outrun;
02776    }
02777    ast_debug(1, "Placed channel %s in DAHDI conf %d\n", ast_channel_name(chan), conf->dahdiconf);
02778 
02779    if (!sent_event) {
02780       ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeJoin",
02781          "Channel: %s\r\n"
02782          "Uniqueid: %s\r\n"
02783          "Meetme: %s\r\n"
02784          "Usernum: %d\r\n"
02785          "CallerIDnum: %s\r\n"
02786          "CallerIDname: %s\r\n"
02787          "ConnectedLineNum: %s\r\n"
02788          "ConnectedLineName: %s\r\n",
02789          ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno,
02790          user->user_no,
02791          S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
02792          S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>"),
02793          S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
02794          S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<unknown>")
02795          );
02796       sent_event = 1;
02797    }
02798 
02799    if (!firstpass && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
02800       !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
02801       firstpass = 1;
02802       if (!ast_test_flag64(confflags, CONFFLAG_QUIET))
02803          if (!ast_test_flag64(confflags, CONFFLAG_WAITMARKED) || (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
02804             (conf->markedusers >= 1))) {
02805             conf_play(chan, conf, ENTER);
02806          }
02807    }
02808 
02809    conf_flush(fd, chan);
02810 
02811    if (dsp)
02812       ast_dsp_free(dsp);
02813 
02814    if (!(dsp = ast_dsp_new())) {
02815       ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
02816       res = -1;
02817    }
02818 
02819    if (ast_test_flag64(confflags, CONFFLAG_AGI)) {
02820       /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
02821          or use default filename of conf-background.agi */
02822 
02823       ast_channel_lock(chan);
02824       if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
02825          agifile = ast_strdupa(tmpvar);
02826       } else {
02827          agifile = ast_strdupa(agifiledefault);
02828       }
02829       ast_channel_unlock(chan);
02830       
02831       if (user->dahdichannel) {
02832          /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
02833          x = 1;
02834          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02835       }
02836       /* Find a pointer to the agi app and execute the script */
02837       agi_app = pbx_findapp("agi");
02838       if (agi_app) {
02839          ret = pbx_exec(chan, agi_app, agifile);
02840       } else {
02841          ast_log(LOG_WARNING, "Could not find application (agi)\n");
02842          ret = -2;
02843       }
02844       if (user->dahdichannel) {
02845          /*  Remove CONFMUTE mode on DAHDI channel */
02846          x = 0;
02847          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02848       }
02849    } else {
02850       if (user->dahdichannel && ast_test_flag64(confflags, CONFFLAG_STARMENU)) {
02851          /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
02852          x = 1;
02853          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02854       }  
02855       for (;;) {
02856          int menu_was_active = 0;
02857 
02858          outfd = -1;
02859          ms = -1;
02860          now = ast_tvnow();
02861 
02862          if (rt_schedule && conf->endtime) {
02863             char currenttime[32];
02864             long localendtime = 0;
02865             int extended = 0;
02866             struct ast_tm tm;
02867             struct ast_variable *var, *origvar;
02868             struct timeval tmp;
02869 
02870             if (now.tv_sec % 60 == 0) {
02871                if (!checked) {
02872                   ast_localtime(&now, &tm, NULL);
02873                   ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02874                   var = origvar = ast_load_realtime("meetme", "confno",
02875                      conf->confno, "starttime <=", currenttime,
02876                       "endtime >=", currenttime, NULL);
02877 
02878                   for ( ; var; var = var->next) {
02879                      if (!strcasecmp(var->name, "endtime")) {
02880                         struct ast_tm endtime_tm;
02881                         ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
02882                         tmp = ast_mktime(&endtime_tm, NULL);
02883                         localendtime = tmp.tv_sec;
02884                      }
02885                   }
02886                   ast_variables_destroy(origvar);
02887 
02888                   /* A conference can be extended from the
02889                      Admin/User menu or by an external source */
02890                   if (localendtime > conf->endtime){
02891                      conf->endtime = localendtime;
02892                      extended = 1;
02893                   }
02894 
02895                   if (conf->endtime && (now.tv_sec >= conf->endtime)) {
02896                      ast_verbose("Quitting time...\n");
02897                      goto outrun;
02898                   }
02899 
02900                   if (!announcement_played && conf->endalert) {
02901                      if (now.tv_sec + conf->endalert >= conf->endtime) {
02902                         if (!ast_streamfile(chan, "conf-will-end-in", ast_channel_language(chan)))
02903                            ast_waitstream(chan, "");
02904                         ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", ast_channel_language(chan));
02905                         if (!ast_streamfile(chan, "minutes", ast_channel_language(chan)))
02906                            ast_waitstream(chan, "");
02907                         if (musiconhold) {
02908                            conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02909                         }
02910                         announcement_played = 1;
02911                      }
02912                   }
02913 
02914                   if (extended) {
02915                      announcement_played = 0;
02916                   }
02917 
02918                   checked = 1;
02919                }
02920             } else {
02921                checked = 0;
02922             }
02923          }
02924 
02925          if (user->kicktime && (user->kicktime <= now.tv_sec)) {
02926             if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
02927                ret = 0;
02928             } else {
02929                ret = -1;
02930             }
02931             break;
02932          }
02933   
02934          to = -1;
02935          if (user->timelimit) {
02936             int minutes = 0, seconds = 0, remain = 0;
02937  
02938             to = ast_tvdiff_ms(nexteventts, now);
02939             if (to < 0) {
02940                to = 0;
02941             }
02942             time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
02943             if (time_left_ms < to) {
02944                to = time_left_ms;
02945             }
02946    
02947             if (time_left_ms <= 0) {
02948                if (user->end_sound) {                 
02949                   res = ast_streamfile(chan, user->end_sound, ast_channel_language(chan));
02950                   res = ast_waitstream(chan, "");
02951                }
02952                if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
02953                   ret = 0;
02954                } else {
02955                   ret = -1;
02956                }
02957                break;
02958             }
02959             
02960             if (!to) {
02961                if (time_left_ms >= 5000) {                  
02962                   
02963                   remain = (time_left_ms + 500) / 1000;
02964                   if (remain / 60 >= 1) {
02965                      minutes = remain / 60;
02966                      seconds = remain % 60;
02967                   } else {
02968                      seconds = remain;
02969                   }
02970                   
02971                   /* force the time left to round up if appropriate */
02972                   if (user->warning_sound && user->play_warning) {
02973                      if (!strcmp(user->warning_sound, "timeleft")) {
02974                         
02975                         res = ast_streamfile(chan, "vm-youhave", ast_channel_language(chan));
02976                         res = ast_waitstream(chan, "");
02977                         if (minutes) {
02978                            res = ast_say_number(chan, minutes, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
02979                            res = ast_streamfile(chan, "queue-minutes", ast_channel_language(chan));
02980                            res = ast_waitstream(chan, "");
02981                         }
02982                         if (seconds) {
02983                            res = ast_say_number(chan, seconds, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
02984                            res = ast_streamfile(chan, "queue-seconds", ast_channel_language(chan));
02985                            res = ast_waitstream(chan, "");
02986                         }
02987                      } else {
02988                         res = ast_streamfile(chan, user->warning_sound, ast_channel_language(chan));
02989                         res = ast_waitstream(chan, "");
02990                      }
02991                      if (musiconhold) {
02992                         conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02993                      }
02994                   }
02995                }
02996                if (user->warning_freq) {
02997                   nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
02998                } else {
02999                   nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
03000                }
03001             }
03002          }
03003 
03004          now = ast_tvnow();
03005          if (timeout && now.tv_sec >= timeout) {
03006             if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
03007                ret = 0;
03008             } else {
03009                ret = -1;
03010             }
03011             break;
03012          }
03013 
03014          /* if we have just exited from the menu, and the user had a channel-driver
03015             volume adjustment, restore it
03016          */
03017          if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual) {
03018             set_talk_volume(user, user->listen.desired);
03019          }
03020 
03021          menu_was_active = menu_active;
03022 
03023          currentmarked = conf->markedusers;
03024          if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
03025              ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
03026              ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
03027              lastmarked == 0) {
03028             if (currentmarked == 1 && conf->users > 1) {
03029                ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
03030                if (conf->users - 1 == 1) {
03031                   if (!ast_streamfile(chan, "conf-userwilljoin", ast_channel_language(chan))) {
03032                      ast_waitstream(chan, "");
03033                   }
03034                } else {
03035                   if (!ast_streamfile(chan, "conf-userswilljoin", ast_channel_language(chan))) {
03036                      ast_waitstream(chan, "");
03037                   }
03038                }
03039             }
03040             if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
03041                if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
03042                   ast_waitstream(chan, "");
03043                }
03044             }
03045          }
03046 
03047          /* Update the struct with the actual confflags */
03048          user->userflags = *confflags;
03049 
03050          if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
03051             if (currentmarked == 0) {
03052                if (lastmarked != 0) {
03053                   if (!ast_test_flag64(confflags, CONFFLAG_QUIET)) {
03054                      if (!ast_streamfile(chan, "conf-leaderhasleft", ast_channel_language(chan))) {
03055                         ast_waitstream(chan, "");
03056                      }
03057                   }
03058                   if (ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
03059                      if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
03060                         ret = 0;
03061                      }
03062                      break;
03063                   } else {
03064                      dahdic.confmode = DAHDI_CONF_CONF;
03065                      if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03066                         ast_log(LOG_WARNING, "Error setting conference\n");
03067                         close(fd);
03068                         goto outrun;
03069                      }
03070                   }
03071                }
03072                if (!musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
03073                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03074                   musiconhold = 1;
03075                }
03076             } else if (currentmarked >= 1 && lastmarked == 0) {
03077                /* Marked user entered, so cancel timeout */
03078                timeout = 0;
03079                if (ast_test_flag64(confflags, CONFFLAG_MONITOR)) {
03080                   dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
03081                } else if (ast_test_flag64(confflags, CONFFLAG_TALKER)) {
03082                   dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
03083                } else {
03084                   dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
03085                }
03086                if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03087                   ast_log(LOG_WARNING, "Error setting conference\n");
03088                   close(fd);
03089                   goto outrun;
03090                }
03091                if (musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
03092                   ast_moh_stop(chan);
03093                   musiconhold = 0;
03094                }
03095                if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && 
03096                   !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
03097                   if (!ast_streamfile(chan, "conf-placeintoconf", ast_channel_language(chan))) {
03098                      ast_waitstream(chan, "");
03099                   }
03100                   conf_play(chan, conf, ENTER);
03101                }
03102             }
03103          }
03104 
03105          /* trying to add moh for single person conf */
03106          if (ast_test_flag64(confflags, CONFFLAG_MOH) && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
03107             if (conf->users == 1) {
03108                if (!musiconhold) {
03109                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03110                   musiconhold = 1;
03111                } 
03112             } else {
03113                if (musiconhold) {
03114                   ast_moh_stop(chan);
03115                   musiconhold = 0;
03116                }
03117             }
03118          }
03119          
03120          /* Leave if the last marked user left */
03121          if (currentmarked == 0 && lastmarked != 0 && ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
03122             if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
03123                ret = 0;
03124             } else {
03125                ret = -1;
03126             }
03127             break;
03128          }
03129    
03130          /* Check if my modes have changed */
03131 
03132          /* If I should be muted but am still talker, mute me */
03133          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
03134             dahdic.confmode ^= DAHDI_CONF_TALKER;
03135             if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03136                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
03137                ret = -1;
03138                break;
03139             }
03140 
03141             /* Indicate user is not talking anymore - change him to unmonitored state */
03142             if (ast_test_flag64(confflags,  (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) {
03143                set_user_talking(chan, conf, user, -1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
03144             }
03145 
03146             ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute",
03147                   "Channel: %s\r\n"
03148                   "Uniqueid: %s\r\n"
03149                   "Meetme: %s\r\n"
03150                   "Usernum: %i\r\n"
03151                   "Status: on\r\n",
03152                   ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
03153          }
03154 
03155          /* If I should be un-muted but am not talker, un-mute me */
03156          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
03157             dahdic.confmode |= DAHDI_CONF_TALKER;
03158             if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03159                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
03160                ret = -1;
03161                break;
03162             }
03163 
03164             ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeMute",
03165                   "Channel: %s\r\n"
03166                   "Uniqueid: %s\r\n"
03167                   "Meetme: %s\r\n"
03168                   "Usernum: %i\r\n"
03169                   "Status: off\r\n",
03170                   ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
03171          }
03172          
03173          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
03174             (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
03175             talkreq_manager = 1;
03176 
03177             ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest",
03178                      "Channel: %s\r\n"
03179                            "Uniqueid: %s\r\n"
03180                            "Meetme: %s\r\n"
03181                            "Usernum: %i\r\n"
03182                            "Status: on\r\n",
03183                            ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
03184          }
03185 
03186          
03187          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
03188             !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
03189             talkreq_manager = 0;
03190             ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalkRequest",
03191                      "Channel: %s\r\n"
03192                            "Uniqueid: %s\r\n"
03193                            "Meetme: %s\r\n"
03194                            "Usernum: %i\r\n"
03195                            "Status: off\r\n",
03196                           ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no);
03197          }
03198 
03199          /* If user have been hung up, exit the conference */
03200          if (user->adminflags & ADMINFLAG_HANGUP) {
03201             ret = 0;
03202             break;
03203          }
03204 
03205          /* If I have been kicked, exit the conference */
03206          if (user->adminflags & ADMINFLAG_KICKME) {
03207             /* You have been kicked. */
03208             if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && 
03209                !ast_streamfile(chan, "conf-kicked", ast_channel_language(chan))) {
03210                ast_waitstream(chan, "");
03211             }
03212             ret = 0;
03213             break;
03214          }
03215 
03216          c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
03217 
03218          if (c) {
03219             char dtmfstr[2] = "";
03220 
03221             if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) {
03222                if (using_pseudo) {
03223                   /* Kill old pseudo */
03224                   close(fd);
03225                   using_pseudo = 0;
03226                }
03227                ast_debug(1, "Ooh, something swapped out under us, starting over\n");
03228                retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0);
03229                user->dahdichannel = !retrydahdi;
03230                goto dahdiretry;
03231             }
03232             if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
03233                f = ast_read_noaudio(c);
03234             } else {
03235                f = ast_read(c);
03236             }
03237             if (!f) {
03238                break;
03239             }
03240             if (f->frametype == AST_FRAME_DTMF) {
03241                dtmfstr[0] = f->subclass.integer;
03242                dtmfstr[1] = '\0';
03243             }
03244 
03245             if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) {
03246                if (user->talk.actual) {
03247                   ast_frame_adjust_volume(f, user->talk.actual);
03248                }
03249 
03250                if (ast_test_flag64(confflags, (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER))) {
03251                   if (user->talking == -1) {
03252                      user->talking = 0;
03253                   }
03254 
03255                   res = ast_dsp_silence(dsp, f, &totalsilence);
03256                   if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
03257                      set_user_talking(chan, conf, user, 1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
03258                   }
03259 
03260                   if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
03261                      set_user_talking(chan, conf, user, 0, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
03262                   }
03263                }
03264                if (using_pseudo) {
03265                   /* Absolutely do _not_ use careful_write here...
03266                      it is important that we read data from the channel
03267                      as fast as it arrives, and feed it into the conference.
03268                      The buffering in the pseudo channel will take care of any
03269                      timing differences, unless they are so drastic as to lose
03270                      audio frames (in which case carefully writing would only
03271                      have delayed the audio even further).
03272                   */
03273                   /* As it turns out, we do want to use careful write.  We just
03274                      don't want to block, but we do want to at least *try*
03275                      to write out all the samples.
03276                    */
03277                   if (user->talking || !ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER)) {
03278                      careful_write(fd, f->data.ptr, f->datalen, 0);
03279                   }
03280                }
03281             } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '*') && ast_test_flag64(confflags, CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
03282                if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
03283                   conf_queue_dtmf(conf, user, f);
03284                }
03285                if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
03286                   ast_log(LOG_WARNING, "Error setting conference\n");
03287                   close(fd);
03288                   ast_frfree(f);
03289                   goto outrun;
03290                }
03291 
03292                /* if we are entering the menu, and the user has a channel-driver
03293                   volume adjustment, clear it
03294                */
03295                if (!menu_active && user->talk.desired && !user->talk.actual) {
03296                   set_talk_volume(user, 0);
03297                }
03298 
03299                if (musiconhold) {
03300                      ast_moh_stop(chan);
03301                }
03302                if (menu8_active) {
03303                   /* *8 Submenu */
03304                   dtmf = f->subclass.integer;
03305                   if (dtmf) {
03306                      int keepplaying;
03307                      int playednamerec;
03308                      struct ao2_iterator user_iter;
03309                      struct ast_conf_user *usr = NULL;
03310                      switch(dtmf) {
03311                      case '1': /* *81 Roll call */
03312                         keepplaying = 1;
03313                         playednamerec = 0;
03314                         if (conf->users == 1) {
03315                            if (keepplaying && !ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
03316                               res = ast_waitstream(chan, AST_DIGIT_ANY);
03317                               ast_stopstream(chan);
03318                               if (res > 0)
03319                                  keepplaying = 0;
03320                            }
03321                         } else if (conf->users == 2) {
03322                            if (keepplaying && !ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
03323                               res = ast_waitstream(chan, AST_DIGIT_ANY);
03324                               ast_stopstream(chan);
03325                               if (res > 0)
03326                                  keepplaying = 0;
03327                            }
03328                         } else {
03329                            if (keepplaying && !ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
03330                               res = ast_waitstream(chan, AST_DIGIT_ANY);
03331                               ast_stopstream(chan);
03332                               if (res > 0)
03333                                  keepplaying = 0;
03334                            }
03335                            if (keepplaying) {
03336                               res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
03337                               if (res > 0)
03338                                  keepplaying = 0;
03339                            }
03340                            if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
03341                               res = ast_waitstream(chan, AST_DIGIT_ANY);
03342                               ast_stopstream(chan);
03343                               if (res > 0)
03344                                  keepplaying = 0;
03345                            }
03346                         }
03347                         user_iter = ao2_iterator_init(conf->usercontainer, 0);
03348                         while((usr = ao2_iterator_next(&user_iter))) {
03349                            if (ast_fileexists(usr->namerecloc, NULL, NULL)) {
03350                               if (keepplaying && !ast_streamfile(chan, usr->namerecloc, ast_channel_language(chan))) {
03351                                  res = ast_waitstream(chan, AST_DIGIT_ANY);
03352                                  ast_stopstream(chan);
03353                                  if (res > 0)
03354                                     keepplaying = 0;
03355                               }
03356                               playednamerec = 1;
03357                            }
03358                            ao2_ref(usr, -1);
03359                         }
03360                         ao2_iterator_destroy(&user_iter);
03361                         if (keepplaying && playednamerec && !ast_streamfile(chan, "conf-roll-callcomplete", ast_channel_language(chan))) {
03362                            res = ast_waitstream(chan, AST_DIGIT_ANY);
03363                            ast_stopstream(chan);
03364                            if (res > 0)
03365                               keepplaying = 0;
03366                         }
03367                         break;
03368                      case '2': /* *82 Eject all non-admins */
03369                         if (conf->users == 1) {
03370                            if(!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan)))
03371                               ast_waitstream(chan, "");
03372                         } else {
03373                            ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_kickme_cb, &conf);
03374                         }
03375                         ast_stopstream(chan);
03376                         break;
03377                      case '3': /* *83 (Admin) mute/unmute all non-admins */
03378                         if(conf->gmuted) {
03379                            conf->gmuted = 0;
03380                            ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, &conf);
03381                            if (!ast_streamfile(chan, "conf-now-unmuted", ast_channel_language(chan)))
03382                               ast_waitstream(chan, "");
03383                         } else {
03384                            conf->gmuted = 1;
03385                            ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_muted_cb, &conf);
03386                            if (!ast_streamfile(chan, "conf-now-muted", ast_channel_language(chan)))
03387                               ast_waitstream(chan, "");
03388                         }
03389                         ast_stopstream(chan);
03390                         break;
03391                      case '4': /* *84 Record conference */
03392                         if (conf->recording != MEETME_RECORD_ACTIVE) {
03393                            ast_set_flag64(confflags, CONFFLAG_RECORDCONF);
03394 
03395                            if (!conf->recordingfilename) {
03396                               const char *var;
03397                               ast_channel_lock(chan);
03398                               if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
03399                                  conf->recordingfilename = ast_strdup(var);
03400                               }
03401                               if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
03402                                  conf->recordingformat = ast_strdup(var);
03403                               }
03404                               ast_channel_unlock(chan);
03405                               if (!conf->recordingfilename) {
03406                                  snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
03407                                  conf->recordingfilename = ast_strdup(recordingtmp);
03408                               }
03409                               if (!conf->recordingformat) {
03410                                  conf->recordingformat = ast_strdup("wav");
03411                               }
03412                               ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
03413                                     conf->confno, conf->recordingfilename, conf->recordingformat);
03414                            }
03415 
03416                            ast_mutex_lock(&conf->recordthreadlock);
03417                            if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, chan, "pseudo", NULL)))) {
03418                               ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
03419                               ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
03420                               dahdic.chan = 0;
03421                               dahdic.confno = conf->dahdiconf;
03422                               dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
03423                               if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
03424                                  ast_log(LOG_WARNING, "Error starting listen channel\n");
03425                                  ast_hangup(conf->lchan);
03426                                  conf->lchan = NULL;
03427                               } else {
03428                                  ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
03429                               }
03430                            }
03431                            ast_mutex_unlock(&conf->recordthreadlock);
03432 
03433                            if (!ast_streamfile(chan, "conf-now-recording", ast_channel_language(chan)))
03434                               ast_waitstream(chan, "");
03435 
03436                         }
03437 
03438                         ast_stopstream(chan);
03439                         break;
03440                      default:
03441                         if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan)))
03442                            ast_waitstream(chan, "");
03443                         ast_stopstream(chan);
03444                         break;
03445                      }
03446                   }
03447 
03448                   menu8_active = 0;
03449                   menu_active = 0;
03450                } else if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
03451                   /* Admin menu */
03452                   if (!menu_active) {
03453                      menu_active = 1;
03454                      /* Record this sound! */
03455                      if (!ast_streamfile(chan, "conf-adminmenu-162", ast_channel_language(chan))) {
03456                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
03457                         ast_stopstream(chan);
03458                      } else {
03459                         dtmf = 0;
03460                      }
03461                   } else {
03462                      dtmf = f->subclass.integer;
03463                   }
03464                   if (dtmf) {
03465                      switch(dtmf) {
03466                      case '1': /* Un/Mute */
03467                         menu_active = 0;
03468 
03469                         /* for admin, change both admin and use flags */
03470                         if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
03471                            user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
03472                         } else {
03473                            user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
03474                         }
03475 
03476                         if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
03477                            if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
03478                               ast_waitstream(chan, "");
03479                            }
03480                         } else {
03481                            if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
03482                               ast_waitstream(chan, "");
03483                            }
03484                         }
03485                         break;
03486                      case '2': /* Un/Lock the Conference */
03487                         menu_active = 0;
03488                         if (conf->locked) {
03489                            conf->locked = 0;
03490                            if (!ast_streamfile(chan, "conf-unlockednow", ast_channel_language(chan))) {
03491                               ast_waitstream(chan, "");
03492                            }
03493                         } else {
03494                            conf->locked = 1;
03495                            if (!ast_streamfile(chan, "conf-lockednow", ast_channel_language(chan))) {
03496                               ast_waitstream(chan, "");
03497                            }
03498                         }
03499                         break;
03500                      case '3': /* Eject last user */
03501                      {
03502                         struct ast_conf_user *usr = NULL;
03503                         int max_no = 0;
03504                         ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
03505                         menu_active = 0;
03506                         usr = ao2_find(conf->usercontainer, &max_no, 0);
03507                         if ((ast_channel_name(usr->chan) == ast_channel_name(chan)) || ast_test_flag64(&usr->userflags, CONFFLAG_ADMIN)) {
03508                            if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
03509                               ast_waitstream(chan, "");
03510                            }
03511                         } else {
03512                            usr->adminflags |= ADMINFLAG_KICKME;
03513                         }
03514                         ao2_ref(usr, -1);
03515                         ast_stopstream(chan);
03516                         break;   
03517                      }
03518                      case '4':
03519                         tweak_listen_volume(user, VOL_DOWN);
03520                         break;
03521                      case '5':
03522                         /* Extend RT conference */
03523                         if (rt_schedule) {
03524                            if (!rt_extend_conf(conf->confno)) {
03525                               if (!ast_streamfile(chan, "conf-extended", ast_channel_language(chan))) {
03526                                  ast_waitstream(chan, "");
03527                               }
03528                            } else {
03529                               if (!ast_streamfile(chan, "conf-nonextended", ast_channel_language(chan))) {
03530                                  ast_waitstream(chan, "");
03531                               }
03532                            }
03533                            ast_stopstream(chan);
03534                         }
03535                         menu_active = 0;
03536                         break;
03537                      case '6':
03538                         tweak_listen_volume(user, VOL_UP);
03539                         break;
03540                      case '7':
03541                         tweak_talk_volume(user, VOL_DOWN);
03542                         break;
03543                      case '8':
03544                         menu8_active = 1;
03545                         break;
03546                      case '9':
03547                         tweak_talk_volume(user, VOL_UP);
03548                         break;
03549                      default:
03550                         menu_active = 0;
03551                         /* Play an error message! */
03552                         if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
03553                            ast_waitstream(chan, "");
03554                         }
03555                         break;
03556                      }
03557                   }
03558                } else {
03559                   /* User menu */
03560                   if (!menu_active) {
03561                      menu_active = 1;
03562                      if (!ast_streamfile(chan, "conf-usermenu-162", ast_channel_language(chan))) {
03563                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
03564                         ast_stopstream(chan);
03565                      } else {
03566                         dtmf = 0;
03567                      }
03568                   } else {
03569                      dtmf = f->subclass.integer;
03570                   }
03571                   if (dtmf) {
03572                      switch (dtmf) {
03573                      case '1': /* Un/Mute */
03574                         menu_active = 0;
03575 
03576                         /* user can only toggle the self-muted state */
03577                         user->adminflags ^= ADMINFLAG_SELFMUTED;
03578 
03579                         /* they can't override the admin mute state */
03580                         if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
03581                            if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
03582                               ast_waitstream(chan, "");
03583                            }
03584                         } else {
03585                            if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
03586                               ast_waitstream(chan, "");
03587                            }
03588                         }
03589                         break;
03590                      case '2':
03591                         menu_active = 0;
03592                         if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
03593                            user->adminflags |= ADMINFLAG_T_REQUEST;
03594                         }
03595                            
03596                         if (user->adminflags & ADMINFLAG_T_REQUEST) {
03597                            if (!ast_streamfile(chan, "beep", ast_channel_language(chan))) {
03598                               ast_waitstream(chan, "");
03599                            }
03600                         }
03601                         break;
03602                      case '4':
03603                         tweak_listen_volume(user, VOL_DOWN);
03604                         break;
03605                      case '5':
03606                         /* Extend RT conference */
03607                         if (rt_schedule) {
03608                            rt_extend_conf(conf->confno);
03609                         }
03610                         menu_active = 0;
03611                         break;
03612                      case '6':
03613                         tweak_listen_volume(user, VOL_UP);
03614                         break;
03615                      case '7':
03616                         tweak_talk_volume(user, VOL_DOWN);
03617                         break;
03618                      case '8':
03619                         menu_active = 0;
03620                         break;
03621                      case '9':
03622                         tweak_talk_volume(user, VOL_UP);
03623                         break;
03624                      default:
03625                         menu_active = 0;
03626                         if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
03627                            ast_waitstream(chan, "");
03628                         }
03629                         break;
03630                      }
03631                   }
03632                }
03633                if (musiconhold && !menu_active) {
03634                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03635                }
03636 
03637                if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03638                   ast_log(LOG_WARNING, "Error setting conference\n");
03639                   close(fd);
03640                   ast_frfree(f);
03641                   goto outrun;
03642                }
03643 
03644                conf_flush(fd, chan);
03645             /*
03646              * Since options using DTMF could absorb DTMF meant for the
03647              * conference menu, we have to check them after the menu.
03648              */
03649             } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
03650                if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
03651                   conf_queue_dtmf(conf, user, f);
03652                }
03653 
03654                if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
03655                   ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
03656                   ret = 0;
03657                   ast_frfree(f);
03658                   break;
03659                } else {
03660                   ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
03661                }
03662             } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_KEYEXIT) &&
03663                (strchr(exitkeys, f->subclass.integer))) {
03664                pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
03665 
03666                if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
03667                   conf_queue_dtmf(conf, user, f);
03668                }
03669                ret = 0;
03670                ast_frfree(f);
03671                break;
03672             } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
03673                && ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
03674                conf_queue_dtmf(conf, user, f);
03675             } else if (ast_test_flag64(confflags, CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
03676                switch (f->subclass.integer) {
03677                case AST_CONTROL_HOLD:
03678                   sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
03679                   break;
03680                default:
03681                   break;
03682                }
03683             } else if (f->frametype == AST_FRAME_NULL) {
03684                /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
03685             } else if (f->frametype == AST_FRAME_CONTROL) {
03686                switch (f->subclass.integer) {
03687                case AST_CONTROL_BUSY:
03688                case AST_CONTROL_CONGESTION:
03689                   ast_frfree(f);
03690                   goto outrun;
03691                   break;
03692                default:
03693                   ast_debug(1,
03694                      "Got ignored control frame on channel %s, f->frametype=%d,f->subclass=%d\n",
03695                      ast_channel_name(chan), f->frametype, f->subclass.integer);
03696                }
03697             } else {
03698                ast_debug(1,
03699                   "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
03700                   ast_channel_name(chan), f->frametype, f->subclass.integer);
03701             }
03702             ast_frfree(f);
03703          } else if (outfd > -1) {
03704             res = read(outfd, buf, CONF_SIZE);
03705             if (res > 0) {
03706                memset(&fr, 0, sizeof(fr));
03707                fr.frametype = AST_FRAME_VOICE;
03708                ast_format_set(&fr.subclass.format, AST_FORMAT_SLINEAR, 0);
03709                fr.datalen = res;
03710                fr.samples = res / 2;
03711                fr.data.ptr = buf;
03712                fr.offset = AST_FRIENDLY_OFFSET;
03713                if (!user->listen.actual &&
03714                   (ast_test_flag64(confflags, CONFFLAG_MONITOR) ||
03715                    (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
03716                    (!user->talking && ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER))
03717                    )) {
03718                   int idx;
03719                   for (idx = 0; idx < AST_FRAME_BITS; idx++) {
03720                      if (ast_format_to_old_bitfield(&chan->rawwriteformat) & (1 << idx)) {
03721                         break;
03722                      }
03723                   }
03724                   if (idx >= AST_FRAME_BITS) {
03725                      goto bailoutandtrynormal;
03726                   }
03727                   ast_mutex_lock(&conf->listenlock);
03728                   if (!conf->transframe[idx]) {
03729                      if (conf->origframe) {
03730                         if (musiconhold && !ast_dsp_silence(dsp, conf->origframe, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
03731                            ast_moh_stop(chan);
03732                            mohtempstopped = 1;
03733                         }
03734                         if (!conf->transpath[idx]) {
03735                            struct ast_format src;
03736                            struct ast_format dst;
03737                            ast_format_set(&src, AST_FORMAT_SLINEAR, 0);
03738                            ast_format_from_old_bitfield(&dst, (1 << idx));
03739                            conf->transpath[idx] = ast_translator_build_path(&dst, &src);
03740                         }
03741                         if (conf->transpath[idx]) {
03742                            conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
03743                            if (!conf->transframe[idx]) {
03744                               conf->transframe[idx] = &ast_null_frame;
03745                            }
03746                         }
03747                      }
03748                   }
03749                   if (conf->transframe[idx]) {
03750                      if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
03751                          can_write(chan, confflags)) {
03752                         struct ast_frame *cur;
03753                         /* the translator may have returned a list of frames, so
03754                            write each one onto the channel
03755                         */
03756                         for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
03757                            if (ast_write(chan, cur)) {
03758                               ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
03759                               break;
03760                            }
03761                         }
03762                         if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
03763                            mohtempstopped = 0;
03764                            ast_moh_start(chan, NULL, NULL);
03765                         }
03766                      }
03767                   } else {
03768                      ast_mutex_unlock(&conf->listenlock);
03769                      goto bailoutandtrynormal;
03770                   }
03771                   ast_mutex_unlock(&conf->listenlock);
03772                } else {
03773 bailoutandtrynormal:
03774                   if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
03775                      ast_moh_stop(chan);
03776                      mohtempstopped = 1;
03777                   }
03778                   if (user->listen.actual) {
03779                      ast_frame_adjust_volume(&fr, user->listen.actual);
03780                   }
03781                   if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
03782                      ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
03783                   }
03784                   if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
03785                      mohtempstopped = 0;
03786                      ast_moh_start(chan, NULL, NULL);
03787                   }
03788                }
03789             } else {
03790                ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
03791             }
03792          }
03793          lastmarked = currentmarked;
03794       }
03795    }
03796 
03797    if (musiconhold) {
03798       ast_moh_stop(chan);
03799    }
03800    
03801    if (using_pseudo) {
03802       close(fd);
03803    } else {
03804       /* Take out of conference */
03805       dahdic.chan = 0;  
03806       dahdic.confno = 0;
03807       dahdic.confmode = 0;
03808       if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03809          ast_log(LOG_WARNING, "Error setting conference\n");
03810       }
03811    }
03812 
03813    reset_volumes(user);
03814 
03815    if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
03816       !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
03817       conf_play(chan, conf, LEAVE);
03818    }
03819 
03820    if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_INTROUSER |CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC) && conf->users > 1) {
03821       struct announce_listitem *item;
03822       if (!(item = ao2_alloc(sizeof(*item), NULL)))
03823          goto outrun;
03824       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
03825       ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
03826       item->confchan = conf->chan;
03827       item->confusers = conf->users;
03828       item->announcetype = CONF_HASLEFT;
03829       if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
03830          item->vmrec = 1;
03831       }
03832       ast_mutex_lock(&conf->announcelistlock);
03833       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
03834       ast_cond_signal(&conf->announcelist_addition);
03835       ast_mutex_unlock(&conf->announcelistlock);
03836    } else if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW) && !ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC) && conf->users == 1) {
03837       /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
03838       ast_filedelete(user->namerecloc, NULL);
03839    }
03840 
03841  outrun:
03842    AST_LIST_LOCK(&confs);
03843 
03844    if (dsp) {
03845       ast_dsp_free(dsp);
03846    }
03847    
03848    if (user->user_no) {
03849       /* Only cleanup users who really joined! */
03850       now = ast_tvnow();
03851 
03852       if (sent_event) {
03853          ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeLeave",
03854             "Channel: %s\r\n"
03855             "Uniqueid: %s\r\n"
03856             "Meetme: %s\r\n"
03857             "Usernum: %d\r\n"
03858             "CallerIDNum: %s\r\n"
03859             "CallerIDName: %s\r\n"
03860             "ConnectedLineNum: %s\r\n"
03861             "ConnectedLineName: %s\r\n"
03862             "Duration: %ld\r\n",
03863             ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno,
03864             user->user_no,
03865             S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
03866             S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>"),
03867             S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
03868             S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<unknown>"),
03869             (long)(now.tv_sec - user->jointime));
03870       }
03871 
03872       if (setusercount) {
03873          conf->users--;
03874          if (rt_log_members) {
03875             /* Update table */
03876             snprintf(members, sizeof(members), "%d", conf->users);
03877             ast_realtime_require_field("meetme",
03878                "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
03879                "members", RQ_UINTEGER1, strlen(members),
03880                NULL);
03881             ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
03882          }
03883          if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
03884             conf->markedusers--;
03885          }
03886       }
03887       /* Remove ourselves from the container */
03888       ao2_unlink(conf->usercontainer, user); 
03889 
03890       /* Change any states */
03891       if (!conf->users) {
03892          ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
03893       }
03894 
03895       /* This flag is meant to kill a conference with only one participant remaining.  */
03896       if (conf->users == 1 && ast_test_flag64(confflags, CONFFLAG_KILL_LAST_MAN_STANDING)) {
03897          ao2_callback(conf->usercontainer, 0, user_set_hangup_cb, NULL);
03898       }
03899 
03900       /* Return the number of seconds the user was in the conf */
03901       snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
03902       pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
03903 
03904       /* Return the RealTime bookid for CDR linking */
03905       if (rt_schedule) {
03906          pbx_builtin_setvar_helper(chan, "MEETMEBOOKID", conf->bookid);
03907       }
03908    }
03909    ao2_ref(user, -1);
03910    AST_LIST_UNLOCK(&confs);
03911 
03912 
03913 conf_run_cleanup:
03914    cap_slin = ast_format_cap_destroy(cap_slin);
03915 
03916    return ret;
03917 }

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

Definition at line 2084 of file app_meetme.c.

References ast_channel_lock, ast_channel_musicclass(), ast_channel_unlock, ast_moh_start(), and ast_strdupa.

Referenced by conf_run().

02085 {
02086    char *original_moh;
02087 
02088    ast_channel_lock(chan);
02089    original_moh = ast_strdupa(ast_channel_musicclass(chan));
02090    ast_channel_musicclass_set(chan, musicclass);
02091    ast_channel_unlock(chan);
02092 
02093    ast_moh_start(chan, original_moh, NULL);
02094 
02095    ast_channel_lock(chan);
02096    ast_channel_musicclass_set(chan, original_moh);
02097    ast_channel_unlock(chan);
02098 }

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

The MeetmeCount application.

Definition at line 4211 of file app_meetme.c.

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

Referenced by load_module().

04212 {
04213    int res = 0;
04214    struct ast_conference *conf;
04215    int count;
04216    char *localdata;
04217    char val[80] = "0"; 
04218    AST_DECLARE_APP_ARGS(args,
04219       AST_APP_ARG(confno);
04220       AST_APP_ARG(varname);
04221    );
04222 
04223    if (ast_strlen_zero(data)) {
04224       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
04225       return -1;
04226    }
04227    
04228    if (!(localdata = ast_strdupa(data)))
04229       return -1;
04230 
04231    AST_STANDARD_APP_ARGS(args, localdata);
04232    
04233    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
04234 
04235    if (conf) {
04236       count = conf->users;
04237       dispose_conf(conf);
04238       conf = NULL;
04239    } else
04240       count = 0;
04241 
04242    if (!ast_strlen_zero(args.varname)) {
04243       /* have var so load it and exit */
04244       snprintf(val, sizeof(val), "%d", count);
04245       pbx_builtin_setvar_helper(chan, args.varname, val);
04246    } else {
04247       if (chan->_state != AST_STATE_UP) {
04248          ast_answer(chan);
04249       }
04250       res = ast_say_number(chan, count, "", ast_channel_language(chan), (char *) NULL); /* Needs gender */
04251    }
04252 
04253    return res;
04254 }

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

Definition at line 6457 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

06458 {
06459    struct sla_trunk_ref *trunk_ref;
06460 
06461    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
06462       return NULL;
06463 
06464    trunk_ref->trunk = trunk;
06465 
06466    return trunk_ref;
06467 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 6665 of file app_meetme.c.

References ast_context_remove_extension(), ast_free, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_MAX_APP, AST_MAX_EXTENSION, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_string_field_free_memory, ast_strlen_zero(), sla_station::autocontext, exten, sla_trunk::name, sla_station::name, PRIORITY_HINT, sla_registrar, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_build_station(), and sla_destroy().

06666 {
06667    struct sla_trunk_ref *trunk_ref;
06668 
06669    if (!ast_strlen_zero(station->autocontext)) {
06670       AST_RWLIST_RDLOCK(&sla_trunks);
06671       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06672          char exten[AST_MAX_EXTENSION];
06673          char hint[AST_MAX_APP];
06674          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06675          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06676          ast_context_remove_extension(station->autocontext, exten, 
06677             1, sla_registrar);
06678          ast_context_remove_extension(station->autocontext, hint, 
06679             PRIORITY_HINT, sla_registrar);
06680       }
06681       AST_RWLIST_UNLOCK(&sla_trunks);
06682    }
06683 
06684    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
06685       ast_free(trunk_ref);
06686 
06687    ast_string_field_free_memory(station);
06688    ast_free(station);
06689 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 6651 of file app_meetme.c.

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

Referenced by sla_build_trunk(), and sla_destroy().

06652 {
06653    struct sla_station_ref *station_ref;
06654 
06655    if (!ast_strlen_zero(trunk->autocontext))
06656       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
06657 
06658    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
06659       ast_free(station_ref);
06660 
06661    ast_string_field_free_memory(trunk);
06662    ast_free(trunk);
06663 }

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

Definition at line 6170 of file app_meetme.c.

References ALL_TRUNK_REFS, args, 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_mutex_lock, ast_mutex_unlock, ast_party_caller_free(), ast_party_caller_init(), ast_set_flag64, ast_strdupa, build_conf(), ast_channel::caller, sla_trunk::chan, sla_trunk_ref::chan, dial_trunk_args::cond, dial_trunk_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_TRUNK, sla_trunk::device, dispose_conf(), MAX_CONFNUM, sla_trunk::name, sla_trunk::on_hold, sla, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, strsep(), sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.

Referenced by sla_station_exec().

06171 {
06172    struct dial_trunk_args *args = data;
06173    struct ast_dial *dial;
06174    char *tech, *tech_data;
06175    enum ast_dial_result dial_res;
06176    char conf_name[MAX_CONFNUM];
06177    struct ast_conference *conf;
06178    struct ast_flags64 conf_flags = { 0 };
06179    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
06180    int caller_is_saved;
06181    struct ast_party_caller caller;
06182 
06183    if (!(dial = ast_dial_create())) {
06184       ast_mutex_lock(args->cond_lock);
06185       ast_cond_signal(args->cond);
06186       ast_mutex_unlock(args->cond_lock);
06187       return NULL;
06188    }
06189 
06190    tech_data = ast_strdupa(trunk_ref->trunk->device);
06191    tech = strsep(&tech_data, "/");
06192    if (ast_dial_append(dial, tech, tech_data) == -1) {
06193       ast_mutex_lock(args->cond_lock);
06194       ast_cond_signal(args->cond);
06195       ast_mutex_unlock(args->cond_lock);
06196       ast_dial_destroy(dial);
06197       return NULL;
06198    }
06199 
06200    /* Do we need to save of the caller ID data? */
06201    caller_is_saved = 0;
06202    if (!sla.attempt_callerid) {
06203       caller_is_saved = 1;
06204       caller = trunk_ref->chan->caller;
06205       ast_party_caller_init(&trunk_ref->chan->caller);
06206    }
06207 
06208    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
06209 
06210    /* Restore saved caller ID */
06211    if (caller_is_saved) {
06212       ast_party_caller_free(&trunk_ref->chan->caller);
06213       trunk_ref->chan->caller = caller;
06214    }
06215 
06216    if (dial_res != AST_DIAL_RESULT_TRYING) {
06217       ast_mutex_lock(args->cond_lock);
06218       ast_cond_signal(args->cond);
06219       ast_mutex_unlock(args->cond_lock);
06220       ast_dial_destroy(dial);
06221       return NULL;
06222    }
06223 
06224    for (;;) {
06225       unsigned int done = 0;
06226       switch ((dial_res = ast_dial_state(dial))) {
06227       case AST_DIAL_RESULT_ANSWERED:
06228          trunk_ref->trunk->chan = ast_dial_answered(dial);
06229       case AST_DIAL_RESULT_HANGUP:
06230       case AST_DIAL_RESULT_INVALID:
06231       case AST_DIAL_RESULT_FAILED:
06232       case AST_DIAL_RESULT_TIMEOUT:
06233       case AST_DIAL_RESULT_UNANSWERED:
06234          done = 1;
06235       case AST_DIAL_RESULT_TRYING:
06236       case AST_DIAL_RESULT_RINGING:
06237       case AST_DIAL_RESULT_PROGRESS:
06238       case AST_DIAL_RESULT_PROCEEDING:
06239          break;
06240       }
06241       if (done)
06242          break;
06243    }
06244 
06245    if (!trunk_ref->trunk->chan) {
06246       ast_mutex_lock(args->cond_lock);
06247       ast_cond_signal(args->cond);
06248       ast_mutex_unlock(args->cond_lock);
06249       ast_dial_join(dial);
06250       ast_dial_destroy(dial);
06251       return NULL;
06252    }
06253 
06254    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
06255    ast_set_flag64(&conf_flags, 
06256       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
06257       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
06258    conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan, NULL);
06259 
06260    ast_mutex_lock(args->cond_lock);
06261    ast_cond_signal(args->cond);
06262    ast_mutex_unlock(args->cond_lock);
06263 
06264    if (conf) {
06265       conf_run(trunk_ref->trunk->chan, conf, &conf_flags, NULL);
06266       dispose_conf(conf);
06267       conf = NULL;
06268    }
06269 
06270    /* If the trunk is going away, it is definitely now IDLE. */
06271    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06272 
06273    trunk_ref->trunk->chan = NULL;
06274    trunk_ref->trunk->on_hold = 0;
06275 
06276    ast_dial_join(dial);
06277    ast_dial_destroy(dial);
06278 
06279    return NULL;
06280 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Decrement reference counts, as incremented by find_conf().

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

02004 {
02005    int res = 0;
02006    int confno_int = 0;
02007 
02008    AST_LIST_LOCK(&confs);
02009    if (ast_atomic_dec_and_test(&conf->refcount)) {
02010       /* Take the conference room number out of an inuse state */
02011       if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
02012          conf_map[confno_int] = 0;
02013       }
02014       conf_free(conf);
02015       res = 1;
02016    }
02017    AST_LIST_UNLOCK(&confs);
02018 
02019    return res;
02020 }

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

Definition at line 4107 of file app_meetme.c.

References args, AST_APP_ARG, ast_app_getdata(), ast_clear_flag64, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_test_flag64, ast_variable_browse(), build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSER_VMREC, 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().

04109 {
04110    struct ast_config *cfg;
04111    struct ast_variable *var;
04112    struct ast_flags config_flags = { 0 };
04113    struct ast_conference *cnf;
04114 
04115    AST_DECLARE_APP_ARGS(args,
04116       AST_APP_ARG(confno);
04117       AST_APP_ARG(pin);
04118       AST_APP_ARG(pinadmin);
04119    );
04120 
04121    /* Check first in the conference list */
04122    ast_debug(1, "The requested confno is '%s'?\n", confno);
04123    AST_LIST_LOCK(&confs);
04124    AST_LIST_TRAVERSE(&confs, cnf, list) {
04125       ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
04126       if (!strcmp(confno, cnf->confno))
04127          break;
04128    }
04129    if (cnf) {
04130       cnf->refcount += refcount;
04131    }
04132    AST_LIST_UNLOCK(&confs);
04133 
04134    if (!cnf) {
04135       if (dynamic) {
04136          /* No need to parse meetme.conf */
04137          ast_debug(1, "Building dynamic conference '%s'\n", confno);
04138          if (dynamic_pin) {
04139             if (dynamic_pin[0] == 'q') {
04140                /* Query the user to enter a PIN */
04141                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
04142                   return NULL;
04143             }
04144             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan, NULL);
04145          } else {
04146             cnf = build_conf(confno, "", "", make, dynamic, refcount, chan, NULL);
04147          }
04148       } else {
04149          /* Check the config */
04150          cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
04151          if (!cfg) {
04152             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
04153             return NULL;
04154          } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04155             ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
04156             return NULL;
04157          }
04158 
04159          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
04160             char parse[MAX_SETTINGS];
04161 
04162             if (strcasecmp(var->name, "conf"))
04163                continue;
04164 
04165             ast_copy_string(parse, var->value, sizeof(parse));
04166 
04167             AST_STANDARD_APP_ARGS(args, parse);
04168             ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
04169             if (!strcasecmp(args.confno, confno)) {
04170                /* Bingo it's a valid conference */
04171                cnf = build_conf(args.confno,
04172                      S_OR(args.pin, ""),
04173                      S_OR(args.pinadmin, ""),
04174                      make, dynamic, refcount, chan, NULL);
04175                break;
04176             }
04177          }
04178          if (!var) {
04179             ast_debug(1, "%s isn't a valid conference\n", confno);
04180          }
04181          ast_config_destroy(cfg);
04182       }
04183    } else if (dynamic_pin) {
04184       /* Correct for the user selecting 'D' instead of 'd' to have
04185          someone join into a conference that has already been created
04186          with a pin. */
04187       if (dynamic_pin[0] == 'q') {
04188          dynamic_pin[0] = '\0';
04189       }
04190    }
04191 
04192    if (cnf) {
04193       if (confflags && !cnf->chan &&
04194           !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
04195           ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW  | CONFFLAG_INTROUSER_VMREC)) {
04196          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
04197          ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC);
04198       }
04199       
04200       if (confflags && !cnf->chan &&
04201           ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
04202          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
04203          ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
04204       }
04205    }
04206 
04207    return cnf;
04208 }

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

Definition at line 3919 of file app_meetme.c.

References ast_conference::adminopts, ast_app_parse_options64(), ast_channel_language(), ast_channel_lock, ast_channel_uniqueid(), ast_channel_unlock, ast_clear_flag64, ast_copy_flags64, ast_copy_string(), ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), AST_MAX_EXTENSION, ast_mktime(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_test_flag64, ast_tvnow(), ast_variables_destroy(), ast_verb, ast_waitstream(), ast_conference::bookid, build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSER_VMREC, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, ast_conference::confno, DATE_FORMAT, ast_conference::endalert, ast_conference::endtime, ast_flags64::flags, 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_conference::useropts, ast_variable::value, and var.

Referenced by conf_exec().

03921 {
03922    struct ast_variable *var, *origvar;
03923    struct ast_conference *cnf;
03924 
03925    *too_early = 0;
03926 
03927    /* Check first in the conference list */
03928    AST_LIST_LOCK(&confs);
03929    AST_LIST_TRAVERSE(&confs, cnf, list) {
03930       if (!strcmp(confno, cnf->confno)) {
03931          break;
03932       }
03933    }
03934    if (cnf) {
03935       cnf->refcount += refcount;
03936    }
03937    AST_LIST_UNLOCK(&confs);
03938 
03939    if (!cnf) {
03940       char *pin = NULL, *pinadmin = NULL; /* For temp use */
03941       int maxusers = 0;
03942       struct timeval now;
03943       char recordingfilename[256] = "";
03944       char recordingformat[11] = "";
03945       char currenttime[32] = "";
03946       char eatime[32] = "";
03947       char bookid[51] = "";
03948       char recordingtmp[AST_MAX_EXTENSION] = "";
03949       char useropts[OPTIONS_LEN + 1] = ""; /* Used for RealTime conferences */
03950       char adminopts[OPTIONS_LEN + 1] = "";
03951       struct ast_tm tm, etm;
03952       struct timeval endtime = { .tv_sec = 0 };
03953       const char *var2;
03954 
03955       if (rt_schedule) {
03956          now = ast_tvnow();
03957 
03958          ast_localtime(&now, &tm, NULL);
03959          ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03960 
03961          ast_debug(1, "Looking for conference %s that starts after %s\n", confno, currenttime);
03962 
03963          var = ast_load_realtime("meetme", "confno",
03964             confno, "starttime <= ", currenttime, "endtime >= ",
03965             currenttime, NULL);
03966 
03967          if (!var && fuzzystart) {
03968             now = ast_tvnow();
03969             now.tv_sec += fuzzystart;
03970 
03971             ast_localtime(&now, &tm, NULL);
03972             ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03973             var = ast_load_realtime("meetme", "confno",
03974                confno, "starttime <= ", currenttime, "endtime >= ",
03975                currenttime, NULL);
03976          }
03977 
03978          if (!var && earlyalert) {
03979             now = ast_tvnow();
03980             now.tv_sec += earlyalert;
03981             ast_localtime(&now, &etm, NULL);
03982             ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
03983             var = ast_load_realtime("meetme", "confno",
03984                confno, "starttime <= ", eatime, "endtime >= ",
03985                currenttime, NULL);
03986             if (var) {
03987                *too_early = 1;
03988             }
03989          }
03990 
03991       } else {
03992           var = ast_load_realtime("meetme", "confno", confno, NULL);
03993       }
03994 
03995       if (!var) {
03996          return NULL;
03997       }
03998 
03999       if (rt_schedule && *too_early) {
04000          /* Announce that the caller is early and exit */
04001          if (!ast_streamfile(chan, "conf-has-not-started", ast_channel_language(chan))) {
04002             ast_waitstream(chan, "");
04003          }
04004          ast_variables_destroy(var);
04005          return NULL;
04006       }
04007 
04008       for (origvar = var; var; var = var->next) {
04009          if (!strcasecmp(var->name, "pin")) {
04010             pin = ast_strdupa(var->value);
04011          } else if (!strcasecmp(var->name, "adminpin")) {
04012             pinadmin = ast_strdupa(var->value);
04013          } else if (!strcasecmp(var->name, "bookId")) {
04014             ast_copy_string(bookid, var->value, sizeof(bookid));
04015          } else if (!strcasecmp(var->name, "opts")) {
04016             ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
04017          } else if (!strcasecmp(var->name, "maxusers")) {
04018             maxusers = atoi(var->value);
04019          } else if (!strcasecmp(var->name, "adminopts")) {
04020             ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
04021          } else if (!strcasecmp(var->name, "recordingfilename")) {
04022             ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
04023          } else if (!strcasecmp(var->name, "recordingformat")) {
04024             ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
04025          } else if (!strcasecmp(var->name, "endtime")) {
04026             struct ast_tm endtime_tm;
04027             ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
04028             endtime = ast_mktime(&endtime_tm, NULL);
04029          }
04030       }
04031 
04032       ast_variables_destroy(origvar);
04033 
04034       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan, NULL);
04035 
04036       if (cnf) {
04037          struct ast_flags64 tmp_flags;
04038 
04039          cnf->maxusers = maxusers;
04040          cnf->endalert = endalert;
04041          cnf->endtime = endtime.tv_sec;
04042          cnf->useropts = ast_strdup(useropts);
04043          cnf->adminopts = ast_strdup(adminopts);
04044          cnf->bookid = ast_strdup(bookid);
04045          if (!ast_strlen_zero(recordingfilename)) {
04046             cnf->recordingfilename = ast_strdup(recordingfilename);
04047          }
04048          if (!ast_strlen_zero(recordingformat)) {
04049             cnf->recordingformat = ast_strdup(recordingformat);
04050          }
04051 
04052          /* Parse the other options into confflags -- need to do this in two
04053           * steps, because the parse_options routine zeroes the buffer. */
04054          ast_app_parse_options64(meetme_opts, &tmp_flags, optargs, useropts);
04055          ast_copy_flags64(confflags, &tmp_flags, tmp_flags.flags);
04056 
04057          if (strchr(cnf->useropts, 'r')) {
04058             if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */
04059                ast_channel_lock(chan);
04060                if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
04061                   ast_free(cnf->recordingfilename);
04062                   cnf->recordingfilename = ast_strdup(var2);
04063                }
04064                ast_channel_unlock(chan);
04065                if (ast_strlen_zero(cnf->recordingfilename)) {
04066                   snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, ast_channel_uniqueid(chan));
04067                   ast_free(cnf->recordingfilename);
04068                   cnf->recordingfilename = ast_strdup(recordingtmp);
04069                }
04070             }
04071             if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */
04072                ast_channel_lock(chan);
04073                if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
04074                   ast_free(cnf->recordingformat);
04075                   cnf->recordingformat = ast_strdup(var2);
04076                }
04077                ast_channel_unlock(chan);
04078                if (ast_strlen_zero(cnf->recordingformat)) {
04079                   ast_free(cnf->recordingformat);
04080                   cnf->recordingformat = ast_strdup("wav");
04081                }
04082             }
04083             ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
04084          }
04085       }
04086    }
04087 
04088    if (cnf) {
04089       if (confflags->flags && !cnf->chan &&
04090           !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
04091           ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW) | CONFFLAG_INTROUSER_VMREC) {
04092          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
04093          ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC);
04094       }
04095 
04096       if (confflags && !cnf->chan &&
04097           ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
04098          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
04099          ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
04100       }
04101    }
04102 
04103    return cnf;
04104 }

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

Definition at line 4577 of file app_meetme.c.

References ao2_find, and ast_conference::usercontainer.

Referenced by acf_mailbox_exists(), acf_vm_info(), admin_exec(), advanced_options(), calltoken_required(), forward_message(), handle_cli_iax2_prune_realtime(), leave_voicemail(), pp_each_extension_helper(), requirecalltoken_mark_auto(), set_config(), setup_incoming_call(), vm_authenticate(), vm_box_exists(), and vm_execmain().

04578 {
04579    struct ast_conf_user *user = NULL;
04580    int cid;
04581    
04582    sscanf(callerident, "%30i", &cid);
04583    if (conf && callerident) {
04584       user = ao2_find(conf->usercontainer, &cid, 0);
04585       /* reference decremented later in admin_exec */
04586       return user;
04587    }
04588    return NULL;
04589 }

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

Definition at line 2100 of file app_meetme.c.

References CONF_HASJOIN, and CONF_HASLEFT.

Referenced by announce_thread().

02101 {
02102    switch (type) {
02103    case CONF_HASLEFT:
02104       return "conf-hasleft";
02105       break;
02106    case CONF_HASJOIN:
02107       return "conf-hasjoin";
02108       break;
02109    default:
02110       return "";
02111    }
02112 }

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

Definition at line 1016 of file app_meetme.c.

Referenced by meetme_show_cmd().

01017 {
01018    if (x > 0)
01019       return "(talking)";
01020    else if (x < 0)
01021       return "(unmonitored)";
01022    else 
01023       return "(not talking)";
01024 }

static int load_config ( int  reload  )  [static]

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

07120 {
07121    load_config_meetme();
07122 
07123    if (reload && sla.thread != AST_PTHREADT_NULL) {
07124       sla_queue_event(SLA_EVENT_RELOAD);
07125       ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
07126          "and will be completed when the system is idle.\n");
07127       return 0;
07128    }
07129    
07130    return sla_load_config(0);
07131 }

static void load_config_meetme ( void   )  [static]

Definition at line 5142 of file app_meetme.c.

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

Referenced by load_config().

05143 {
05144    struct ast_config *cfg;
05145    struct ast_flags config_flags = { 0 };
05146    const char *val;
05147 
05148    if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
05149       return;
05150    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
05151       ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
05152       return;
05153    }
05154 
05155    audio_buffers = DEFAULT_AUDIO_BUFFERS;
05156 
05157    /*  Scheduling support is off by default */
05158    rt_schedule = 0;
05159    fuzzystart = 0;
05160    earlyalert = 0;
05161    endalert = 0;
05162    extendby = 0;
05163 
05164    /*  Logging of participants defaults to ON for compatibility reasons */
05165    rt_log_members = 1;  
05166 
05167    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
05168       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
05169          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
05170          audio_buffers = DEFAULT_AUDIO_BUFFERS;
05171       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
05172          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
05173             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
05174          audio_buffers = DEFAULT_AUDIO_BUFFERS;
05175       }
05176       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
05177          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
05178    }
05179 
05180    if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
05181       rt_schedule = ast_true(val);
05182    if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
05183       rt_log_members = ast_true(val);
05184    if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
05185       if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
05186          ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
05187          fuzzystart = 0;
05188       } 
05189    }
05190    if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
05191       if ((sscanf(val, "%30d", &earlyalert) != 1)) {
05192          ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
05193          earlyalert = 0;
05194       } 
05195    }
05196    if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
05197       if ((sscanf(val, "%30d", &endalert) != 1)) {
05198          ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
05199          endalert = 0;
05200       } 
05201    }
05202    if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
05203       if ((sscanf(val, "%30d", &extendby) != 1)) {
05204          ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
05205          extendby = 0;
05206       } 
05207    }
05208 
05209    ast_config_destroy(cfg);
05210 }

static int load_module ( void   )  [static]

Definition at line 7345 of file app_meetme.c.

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

07346 {
07347    int res = 0;
07348 
07349    res |= load_config(0);
07350 
07351    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07352    res |= ast_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute);
07353    res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute);
07354    res |= ast_manager_register_xml("MeetmeList", EVENT_FLAG_REPORTING, action_meetmelist);
07355    res |= ast_manager_register_xml("MeetmeListRooms", EVENT_FLAG_REPORTING, action_meetmelistrooms);
07356    res |= ast_register_application_xml(app4, channel_admin_exec);
07357    res |= ast_register_application_xml(app3, admin_exec);
07358    res |= ast_register_application_xml(app2, count_exec);
07359    res |= ast_register_application_xml(app, conf_exec);
07360    res |= ast_register_application_xml(slastation_app, sla_station_exec);
07361    res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
07362 
07363 #ifdef TEST_FRAMEWORK
07364    AST_TEST_REGISTER(test_meetme_data_provider);
07365 #endif
07366    ast_data_register_multiple(meetme_data_providers, ARRAY_LEN(meetme_data_providers));
07367 
07368    res |= ast_devstate_prov_add("Meetme", meetmestate);
07369    res |= ast_devstate_prov_add("SLA", sla_state);
07370 
07371    res |= ast_custom_function_register(&meetme_info_acf);
07372    ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
07373 
07374    return res;
07375 }

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

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

01557 {
01558    /* Process the command */
01559    struct ast_str *cmdline = NULL;
01560    int i = 0;
01561 
01562    switch (cmd) {
01563    case CLI_INIT:
01564       e->command = "meetme {lock|unlock|mute|unmute|kick}";
01565       e->usage =
01566          "Usage: meetme (un)lock|(un)mute|kick <confno> <usernumber>\n"
01567          "       Executes a command for the conference or on a conferee\n";
01568       return NULL;
01569    case CLI_GENERATE:
01570       return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01571    }
01572 
01573    if (a->argc > 8)
01574       ast_cli(a->fd, "Invalid Arguments.\n");
01575    /* Check for length so no buffer will overflow... */
01576    for (i = 0; i < a->argc; i++) {
01577       if (strlen(a->argv[i]) > 100)
01578          ast_cli(a->fd, "Invalid Arguments.\n");
01579    }
01580 
01581    /* Max confno length */
01582    if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01583       return CLI_FAILURE;
01584    }
01585 
01586    if (a->argc < 1) {
01587       ast_free(cmdline);
01588       return CLI_SHOWUSAGE;
01589    }
01590 
01591    ast_str_set(&cmdline, 0, "%s", a->argv[2]);  /* Argv 2: conference number */
01592    if (strstr(a->argv[1], "lock")) {
01593       if (strcmp(a->argv[1], "lock") == 0) {
01594          /* Lock */
01595          ast_str_append(&cmdline, 0, ",L");
01596       } else {
01597          /* Unlock */
01598          ast_str_append(&cmdline, 0, ",l");
01599       }
01600    } else if (strstr(a->argv[1], "mute")) { 
01601       if (a->argc < 4) {
01602          ast_free(cmdline);
01603          return CLI_SHOWUSAGE;
01604       }
01605       if (strcmp(a->argv[1], "mute") == 0) {
01606          /* Mute */
01607          if (strcmp(a->argv[3], "all") == 0) {
01608             ast_str_append(&cmdline, 0, ",N");
01609          } else {
01610             ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);  
01611          }
01612       } else {
01613          /* Unmute */
01614          if (strcmp(a->argv[3], "all") == 0) {
01615             ast_str_append(&cmdline, 0, ",n");
01616          } else {
01617             ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
01618          }
01619       }
01620    } else if (strcmp(a->argv[1], "kick") == 0) {
01621       if (a->argc < 4) {
01622          ast_free(cmdline);
01623          return CLI_SHOWUSAGE;
01624       }
01625       if (strcmp(a->argv[3], "all") == 0) {
01626          /* Kick all */
01627          ast_str_append(&cmdline, 0, ",K");
01628       } else {
01629          /* Kick a single user */
01630          ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
01631       }
01632    } else {
01633       ast_free(cmdline);
01634       return CLI_SHOWUSAGE;
01635    }
01636 
01637    ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
01638 
01639    admin_exec(NULL, ast_str_buffer(cmdline));
01640    ast_free(cmdline);
01641 
01642    return CLI_SUCCESS;
01643 }

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

Definition at line 7208 of file app_meetme.c.

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

07210 {
07211    struct ast_conference *cnf;
07212    struct ast_data *data_meetme, *data_meetme_users;
07213 
07214    AST_LIST_LOCK(&confs);
07215    AST_LIST_TRAVERSE(&confs, cnf, list) {
07216       data_meetme = ast_data_add_node(data_root, "meetme");
07217       if (!data_meetme) {
07218          continue;
07219       }
07220 
07221       ast_data_add_structure(ast_conference, data_meetme, cnf);
07222 
07223       if (ao2_container_count(cnf->usercontainer)) {
07224          data_meetme_users = ast_data_add_node(data_meetme, "users");
07225          if (!data_meetme_users) {
07226             ast_data_remove_node(data_root, data_meetme);
07227             continue;
07228          }
07229 
07230          ao2_callback(cnf->usercontainer, OBJ_NODATA, user_add_provider_cb, data_meetme_users); 
07231       }
07232 
07233       if (!ast_data_search_match(search, data_meetme)) {
07234          ast_data_remove_node(data_root, data_meetme);
07235       }
07236    }
07237    AST_LIST_UNLOCK(&confs);
07238 
07239    return 0;
07240 }

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

Definition at line 1398 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_channel_name(), 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_test_flag64, ast_channel::caller, ast_conf_user::chan, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd(), CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_cli_args::fd, ast_party_caller::id, ast_conference::isdynamic, istalking(), ast_conf_user::jointime, ast_cli_args::line, ast_conference::locked, ast_conference::markedusers, MAX_CONFNUM, MC_DATA_FORMAT, MC_HEADER_FORMAT, ast_cli_args::n, ast_party_id::name, ast_party_id::number, ast_cli_args::pos, S_COR, ast_conference::start, ast_party_name::str, ast_party_number::str, ast_conf_user::talking, total, ast_cli_entry::usage, ast_conf_user::user_no, ast_conference::usercontainer, ast_conf_user::userflags, ast_conference::users, ast_party_name::valid, ast_party_number::valid, and ast_cli_args::word.

01399 {
01400    /* Process the command */
01401    struct ast_conf_user *user;
01402    struct ast_conference *cnf;
01403    int hr, min, sec;
01404    int i = 0, total = 0;
01405    time_t now;
01406    struct ast_str *cmdline = NULL;
01407 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s  %-8s  %-6s\n"
01408 #define MC_DATA_FORMAT "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s  %-6s\n"
01409 
01410    switch (cmd) {
01411    case CLI_INIT:
01412       e->command = "meetme list [concise]";
01413       e->usage =
01414          "Usage: meetme list [concise] <confno> \n"
01415          "       List all or a specific conference.\n";
01416       return NULL;
01417    case CLI_GENERATE:
01418       return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01419    }
01420 
01421    /* Check for length so no buffer will overflow... */
01422    for (i = 0; i < a->argc; i++) {
01423       if (strlen(a->argv[i]) > 100)
01424          ast_cli(a->fd, "Invalid Arguments.\n");
01425    }
01426 
01427    /* Max confno length */
01428    if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01429       return CLI_FAILURE;
01430    }
01431 
01432    if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], "concise"))) {
01433       /* List all the conferences */   
01434       int concise = (a->argc == 3 && !strcasecmp(a->argv[2], "concise"));
01435       now = time(NULL);
01436       AST_LIST_LOCK(&confs);
01437       if (AST_LIST_EMPTY(&confs)) {
01438          if (!concise) {
01439             ast_cli(a->fd, "No active MeetMe conferences.\n");
01440          }
01441          AST_LIST_UNLOCK(&confs);
01442          ast_free(cmdline);
01443          return CLI_SUCCESS;
01444       }
01445       if (!concise) {
01446          ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
01447       }
01448       AST_LIST_TRAVERSE(&confs, cnf, list) {
01449          if (cnf->markedusers == 0) {
01450             ast_str_set(&cmdline, 0, "N/A ");
01451          } else {
01452             ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
01453          }
01454          hr = (now - cnf->start) / 3600;
01455          min = ((now - cnf->start) % 3600) / 60;
01456          sec = (now - cnf->start) % 60;
01457          if (!concise) {
01458             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");
01459          } else {
01460             ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
01461                cnf->confno,
01462                cnf->users,
01463                cnf->markedusers,
01464                hr, min, sec,
01465                cnf->isdynamic,
01466                cnf->locked);
01467          }
01468 
01469          total += cnf->users;
01470       }
01471       AST_LIST_UNLOCK(&confs);
01472       if (!concise) {
01473          ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
01474       }
01475       ast_free(cmdline);
01476       return CLI_SUCCESS;
01477    } else if (strcmp(a->argv[1], "list") == 0) {
01478       struct ao2_iterator user_iter;
01479       int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
01480       /* List all the users in a conference */
01481       if (AST_LIST_EMPTY(&confs)) {
01482          if (!concise) {
01483             ast_cli(a->fd, "No active MeetMe conferences.\n");
01484          }
01485          ast_free(cmdline);
01486          return CLI_SUCCESS;  
01487       }
01488       /* Find the right conference */
01489       AST_LIST_LOCK(&confs);
01490       AST_LIST_TRAVERSE(&confs, cnf, list) {
01491          if (strcmp(cnf->confno, a->argv[2]) == 0) {
01492             break;
01493          }
01494       }
01495       if (!cnf) {
01496          if (!concise)
01497             ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
01498          AST_LIST_UNLOCK(&confs);
01499          ast_free(cmdline);
01500          return CLI_SUCCESS;
01501       }
01502       /* Show all the users */
01503       time(&now);
01504       user_iter = ao2_iterator_init(cnf->usercontainer, 0);
01505       while((user = ao2_iterator_next(&user_iter))) {
01506          hr = (now - user->jointime) / 3600;
01507          min = ((now - user->jointime) % 3600) / 60;
01508          sec = (now - user->jointime) % 60;
01509          if (!concise) {
01510             ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
01511                user->user_no,
01512                S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
01513                S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
01514                ast_channel_name(user->chan),
01515                ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "(Admin)" : "",
01516                ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "(Listen only)" : "",
01517                user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
01518                user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
01519                istalking(user->talking), hr, min, sec); 
01520          } else {
01521             ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
01522                user->user_no,
01523                S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, ""),
01524                S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, ""),
01525                ast_channel_name(user->chan),
01526                ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "1" : "",
01527                ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "1" : "",
01528                user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
01529                user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
01530                user->talking, hr, min, sec);
01531          }
01532          ao2_ref(user, -1);
01533       }
01534       ao2_iterator_destroy(&user_iter);
01535       if (!concise) {
01536          ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
01537       }
01538       AST_LIST_UNLOCK(&confs);
01539       ast_free(cmdline);
01540       return CLI_SUCCESS;
01541    }
01542    if (a->argc < 2) {
01543       ast_free(cmdline);
01544       return CLI_SHOWUSAGE;
01545    }
01546 
01547    ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
01548 
01549    admin_exec(NULL, ast_str_buffer(cmdline));
01550    ast_free(cmdline);
01551 
01552    return CLI_SUCCESS;
01553 }

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

Definition at line 4843 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ao2_find, ao2_ref, ast_channel_name(), ast_channel_uniqueid(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strdupa, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), ast_conf_user::chan, ast_conference::confno, ast_conf_user::list, LOG_NOTICE, ast_conf_user::user_no, and ast_conference::usercontainer.

Referenced by action_meetmemute(), and action_meetmeunmute().

04844 {
04845    struct ast_conference *conf;
04846    struct ast_conf_user *user;
04847    const char *confid = astman_get_header(m, "Meetme");
04848    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
04849    int userno;
04850 
04851    if (ast_strlen_zero(confid)) {
04852       astman_send_error(s, m, "Meetme conference not specified");
04853       return 0;
04854    }
04855 
04856    if (ast_strlen_zero(userid)) {
04857       astman_send_error(s, m, "Meetme user number not specified");
04858       return 0;
04859    }
04860 
04861    userno = strtoul(userid, &userid, 10);
04862 
04863    if (*userid) {
04864       astman_send_error(s, m, "Invalid user number");
04865       return 0;
04866    }
04867 
04868    /* Look in the conference list */
04869    AST_LIST_LOCK(&confs);
04870    AST_LIST_TRAVERSE(&confs, conf, list) {
04871       if (!strcmp(confid, conf->confno))
04872          break;
04873    }
04874 
04875    if (!conf) {
04876       AST_LIST_UNLOCK(&confs);
04877       astman_send_error(s, m, "Meetme conference does not exist");
04878       return 0;
04879    }
04880 
04881    user = ao2_find(conf->usercontainer, &userno, 0);
04882 
04883    if (!user) {
04884       AST_LIST_UNLOCK(&confs);
04885       astman_send_error(s, m, "User number not found");
04886       return 0;
04887    }
04888 
04889    if (mute)
04890       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
04891    else
04892       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
04893 
04894    AST_LIST_UNLOCK(&confs);
04895 
04896    ast_log(LOG_NOTICE, "Requested to %smute conf %s user %d userchan %s uniqueid %s\n", mute ? "" : "un", conf->confno, user->user_no, ast_channel_name(user->chan), ast_channel_uniqueid(user->chan));
04897 
04898    ao2_ref(user, -1);
04899    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
04900    return 0;
04901 }

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

Callback for devicestate providers.

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

05121 {
05122    struct ast_conference *conf;
05123 
05124    /* Find conference */
05125    AST_LIST_LOCK(&confs);
05126    AST_LIST_TRAVERSE(&confs, conf, list) {
05127       if (!strcmp(data, conf->confno))
05128          break;
05129    }
05130    AST_LIST_UNLOCK(&confs);
05131    if (!conf)
05132       return AST_DEVICE_INVALID;
05133 
05134 
05135    /* SKREP to fill */
05136    if (!conf->users)
05137       return AST_DEVICE_NOT_INUSE;
05138 
05139    return AST_DEVICE_INUSE;
05140 }

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

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

06470 {
06471    struct sla_ringing_trunk *ringing_trunk;
06472 
06473    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
06474       return NULL;
06475    
06476    ringing_trunk->trunk = trunk;
06477    ringing_trunk->ring_begin = ast_tvnow();
06478 
06479    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
06480 
06481    ast_mutex_lock(&sla.lock);
06482    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
06483    ast_mutex_unlock(&sla.lock);
06484 
06485    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06486 
06487    return ringing_trunk;
06488 }

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

Definition at line 5055 of file app_meetme.c.

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

05056 {
05057    struct ast_conference *cnf = args;
05058    struct ast_frame *f = NULL;
05059    int flags;
05060    struct ast_filestream *s = NULL;
05061    int res = 0;
05062    int x;
05063    const char *oldrecordingfilename = NULL;
05064 
05065    if (!cnf || !cnf->lchan) {
05066       pthread_exit(0);
05067    }
05068 
05069    ast_stopstream(cnf->lchan);
05070    flags = O_CREAT | O_TRUNC | O_WRONLY;
05071 
05072 
05073    cnf->recording = MEETME_RECORD_ACTIVE;
05074    while (ast_waitfor(cnf->lchan, -1) > -1) {
05075       if (cnf->recording == MEETME_RECORD_TERMINATE) {
05076          AST_LIST_LOCK(&confs);
05077          AST_LIST_UNLOCK(&confs);
05078          break;
05079       }
05080       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
05081          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
05082          oldrecordingfilename = cnf->recordingfilename;
05083       }
05084       
05085       f = ast_read(cnf->lchan);
05086       if (!f) {
05087          res = -1;
05088          break;
05089       }
05090       if (f->frametype == AST_FRAME_VOICE) {
05091          ast_mutex_lock(&cnf->listenlock);
05092          for (x = 0; x < AST_FRAME_BITS; x++) {
05093             /* Free any translations that have occured */
05094             if (cnf->transframe[x]) {
05095                ast_frfree(cnf->transframe[x]);
05096                cnf->transframe[x] = NULL;
05097             }
05098          }
05099          if (cnf->origframe)
05100             ast_frfree(cnf->origframe);
05101          cnf->origframe = ast_frdup(f);
05102          ast_mutex_unlock(&cnf->listenlock);
05103          if (s)
05104             res = ast_writestream(s, f);
05105          if (res) {
05106             ast_frfree(f);
05107             break;
05108          }
05109       }
05110       ast_frfree(f);
05111    }
05112    cnf->recording = MEETME_RECORD_OFF;
05113    if (s)
05114       ast_closestream(s);
05115    
05116    pthread_exit(0);
05117 }

static int reload ( void   )  [static]

Definition at line 7377 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

07378 {
07379    ast_unload_realtime("meetme");
07380    return load_config(1);
07381 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

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

01137 {
01138    signed char zero_volume = 0;
01139 
01140    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
01141    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
01142 }

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

Definition at line 2022 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

02023 {
02024    char currenttime[32];
02025    char endtime[32];
02026    struct timeval now;
02027    struct ast_tm tm;
02028    struct ast_variable *var, *orig_var;
02029    char bookid[51];
02030 
02031    if (!extendby) {
02032       return 0;
02033    }
02034 
02035    now = ast_tvnow();
02036 
02037    ast_localtime(&now, &tm, NULL);
02038    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02039 
02040    var = ast_load_realtime("meetme", "confno",
02041       confno, "startTime<= ", currenttime,
02042       "endtime>= ", currenttime, NULL);
02043 
02044    orig_var = var;
02045 
02046    /* Identify the specific RealTime conference */
02047    while (var) {
02048       if (!strcasecmp(var->name, "bookid")) {
02049          ast_copy_string(bookid, var->value, sizeof(bookid));
02050       }
02051       if (!strcasecmp(var->name, "endtime")) {
02052          ast_copy_string(endtime, var->value, sizeof(endtime));
02053       }
02054 
02055       var = var->next;
02056    }
02057    ast_variables_destroy(orig_var);
02058 
02059    ast_strptime(endtime, DATE_FORMAT, &tm);
02060    now = ast_mktime(&tm, NULL);
02061 
02062    now.tv_sec += extendby;
02063 
02064    ast_localtime(&now, &tm, NULL);
02065    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02066    strcat(currenttime, "0"); /* Seconds needs to be 00 */
02067 
02068    var = ast_load_realtime("meetme", "confno",
02069       confno, "startTime<= ", currenttime,
02070       "endtime>= ", currenttime, NULL);
02071 
02072    /* If there is no conflict with extending the conference, update the DB */
02073    if (!var) {
02074       ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
02075       ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
02076       return 0;
02077 
02078    }
02079 
02080    ast_variables_destroy(var);
02081    return -1;
02082 }

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

Definition at line 5369 of file app_meetme.c.

References sla_trunk::active_stations, admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), args, ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_cond_signal, ast_dial_destroy(), ast_dial_join(), ast_free, ast_mutex_lock, ast_mutex_unlock, ast_set_flag64, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), build_conf(), 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(), sla_trunk::hold_stations, sla_trunk::name, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, run_station_args::station, sla_trunk_ref::trunk, and run_station_args::trunk_ref.

Referenced by sla_handle_dial_state_event().

05370 {
05371    struct sla_station *station;
05372    struct sla_trunk_ref *trunk_ref;
05373    struct ast_str *conf_name = ast_str_create(16);
05374    struct ast_flags64 conf_flags = { 0 };
05375    struct ast_conference *conf;
05376 
05377    {
05378       struct run_station_args *args = data;
05379       station = args->station;
05380       trunk_ref = args->trunk_ref;
05381       ast_mutex_lock(args->cond_lock);
05382       ast_cond_signal(args->cond);
05383       ast_mutex_unlock(args->cond_lock);
05384       /* args is no longer valid here. */
05385    }
05386 
05387    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
05388    ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
05389    ast_set_flag64(&conf_flags, 
05390       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05391    answer_trunk_chan(trunk_ref->chan);
05392    conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan, NULL);
05393    if (conf) {
05394       conf_run(trunk_ref->chan, conf, &conf_flags, NULL);
05395       dispose_conf(conf);
05396       conf = NULL;
05397    }
05398    trunk_ref->chan = NULL;
05399    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05400       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05401       ast_str_append(&conf_name, 0, ",K");
05402       admin_exec(NULL, ast_str_buffer(conf_name));
05403       trunk_ref->trunk->hold_stations = 0;
05404       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05405    }
05406 
05407    ast_dial_join(station->dial);
05408    ast_dial_destroy(station->dial);
05409    station->dial = NULL;
05410    ast_free(conf_name);
05411 
05412    return NULL;
05413 }

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

Definition at line 2180 of file app_meetme.c.

References ast_channel_name(), ast_channel_uniqueid(), ast_manager_event, ast_conference::confno, EVENT_FLAG_CALL, and ast_conf_user::user_no.

Referenced by set_user_talking().

02181 {
02182    ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking",
02183          "Channel: %s\r\n"
02184          "Uniqueid: %s\r\n"
02185          "Meetme: %s\r\n"
02186          "Usernum: %d\r\n"
02187          "Status: %s\r\n",
02188          ast_channel_name(chan), ast_channel_uniqueid(chan), conf->confno, user->user_no, talking ? "on" : "off");
02189 }

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

Definition at line 1065 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

01066 {
01067    char gain_adjust;
01068 
01069    /* attempt to make the adjustment in the channel driver;
01070       if successful, don't adjust in the frame reading routine
01071    */
01072    gain_adjust = gain_map[volume + 5];
01073 
01074    return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
01075 }

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

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

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

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

References send_talking_event(), and ast_conf_user::talking.

Referenced by conf_run().

02192 {
02193    int last_talking = user->talking;
02194    if (last_talking == talking)
02195       return;
02196 
02197    user->talking = talking;
02198 
02199    if (monitor) {
02200       /* Check if talking state changed. Take care of -1 which means unmonitored */
02201       int was_talking = (last_talking > 0);
02202       int now_talking = (talking > 0);
02203       if (was_talking != now_talking) {
02204          send_talking_event(chan, conf, user, now_talking);
02205       }
02206    }
02207 }

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

Definition at line 6809 of file app_meetme.c.

References ast_atomic_fetchadd_int(), ast_free, AST_LIST_INSERT_TAIL, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdupa, create_trunk_ref(), LOG_ERROR, LOG_WARNING, sla_station::name, sla_trunk::name, sla_trunk::num_stations, sla_trunk_ref::ring_delay, sla_trunk_ref::ring_timeout, sla_create_station_ref(), SLA_TRUNK_STATE_IDLE, sla_trunk_ref::state, sla_trunk::stations, strsep(), sla_station::trunks, value, and ast_variable::value.

Referenced by sla_build_station().

06810 {
06811    struct sla_trunk *trunk;
06812    struct sla_trunk_ref *trunk_ref;
06813    struct sla_station_ref *station_ref;
06814    char *trunk_name, *options, *cur;
06815 
06816    options = ast_strdupa(var->value);
06817    trunk_name = strsep(&options, ",");
06818    
06819    AST_RWLIST_RDLOCK(&sla_trunks);
06820    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
06821       if (!strcasecmp(trunk->name, trunk_name))
06822          break;
06823    }
06824 
06825    AST_RWLIST_UNLOCK(&sla_trunks);
06826    if (!trunk) {
06827       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
06828       return;
06829    }
06830    if (!(trunk_ref = create_trunk_ref(trunk)))
06831       return;
06832    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
06833 
06834    while ((cur = strsep(&options, ","))) {
06835       char *name, *value = cur;
06836       name = strsep(&value, "=");
06837       if (!strcasecmp(name, "ringtimeout")) {
06838          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
06839             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
06840                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06841             trunk_ref->ring_timeout = 0;
06842          }
06843       } else if (!strcasecmp(name, "ringdelay")) {
06844          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
06845             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
06846                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06847             trunk_ref->ring_delay = 0;
06848          }
06849       } else {
06850          ast_log(LOG_WARNING, "Invalid option '%s' for "
06851             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
06852       }
06853    }
06854 
06855    if (!(station_ref = sla_create_station_ref(station))) {
06856       ast_free(trunk_ref);
06857       return;
06858    }
06859    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
06860    AST_RWLIST_WRLOCK(&sla_trunks);
06861    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
06862    AST_RWLIST_UNLOCK(&sla_trunks);
06863    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
06864 }

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

Definition at line 6866 of file app_meetme.c.

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

Referenced by sla_load_config().

06867 {
06868    struct sla_station *station;
06869    struct ast_variable *var;
06870    const char *dev;
06871 
06872    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06873       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
06874       return -1;
06875    }
06876 
06877    if (!(station = ast_calloc_with_stringfields(1, struct sla_station, 32))) {
06878       return -1;
06879    }
06880 
06881    ast_string_field_set(station, name, cat);
06882    ast_string_field_set(station, device, dev);
06883 
06884    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06885       if (!strcasecmp(var->name, "trunk"))
06886          sla_add_trunk_to_station(station, var);
06887       else if (!strcasecmp(var->name, "autocontext"))
06888          ast_string_field_set(station, autocontext, var->value);
06889       else if (!strcasecmp(var->name, "ringtimeout")) {
06890          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
06891             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
06892                var->value, station->name);
06893             station->ring_timeout = 0;
06894          }
06895       } else if (!strcasecmp(var->name, "ringdelay")) {
06896          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
06897             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
06898                var->value, station->name);
06899             station->ring_delay = 0;
06900          }
06901       } else if (!strcasecmp(var->name, "hold")) {
06902          if (!strcasecmp(var->value, "private"))
06903             station->hold_access = SLA_HOLD_PRIVATE;
06904          else if (!strcasecmp(var->value, "open"))
06905             station->hold_access = SLA_HOLD_OPEN;
06906          else {
06907             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
06908                var->value, station->name);
06909          }
06910 
06911       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06912          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06913             var->name, var->lineno, SLA_CONFIG_FILE);
06914       }
06915    }
06916 
06917    if (!ast_strlen_zero(station->autocontext)) {
06918       struct ast_context *context;
06919       struct sla_trunk_ref *trunk_ref;
06920       context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
06921       if (!context) {
06922          ast_log(LOG_ERROR, "Failed to automatically find or create "
06923             "context '%s' for SLA!\n", station->autocontext);
06924          destroy_station(station);
06925          return -1;
06926       }
06927       /* The extension for when the handset goes off-hook.
06928        * exten => station1,1,SLAStation(station1) */
06929       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
06930          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
06931          ast_log(LOG_ERROR, "Failed to automatically create extension "
06932             "for trunk '%s'!\n", station->name);
06933          destroy_station(station);
06934          return -1;
06935       }
06936       AST_RWLIST_RDLOCK(&sla_trunks);
06937       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06938          char exten[AST_MAX_EXTENSION];
06939          char hint[AST_MAX_APP];
06940          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06941          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06942          /* Extension for this line button 
06943           * exten => station1_line1,1,SLAStation(station1_line1) */
06944          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
06945             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
06946             ast_log(LOG_ERROR, "Failed to automatically create extension "
06947                "for trunk '%s'!\n", station->name);
06948             destroy_station(station);
06949             return -1;
06950          }
06951          /* Hint for this line button 
06952           * exten => station1_line1,hint,SLA:station1_line1 */
06953          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
06954             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
06955             ast_log(LOG_ERROR, "Failed to automatically create hint "
06956                "for trunk '%s'!\n", station->name);
06957             destroy_station(station);
06958             return -1;
06959          }
06960       }
06961       AST_RWLIST_UNLOCK(&sla_trunks);
06962    }
06963 
06964    AST_RWLIST_WRLOCK(&sla_stations);
06965    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
06966    AST_RWLIST_UNLOCK(&sla_stations);
06967 
06968    return 0;
06969 }

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

Definition at line 6734 of file app_meetme.c.

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

Referenced by sla_load_config().

06735 {
06736    struct sla_trunk *trunk;
06737    struct ast_variable *var;
06738    const char *dev;
06739 
06740    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06741       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
06742       return -1;
06743    }
06744 
06745    if (sla_check_device(dev)) {
06746       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
06747          cat, dev);
06748       return -1;
06749    }
06750 
06751    if (!(trunk = ast_calloc_with_stringfields(1, struct sla_trunk, 32))) {
06752       return -1;
06753    }
06754 
06755    ast_string_field_set(trunk, name, cat);
06756    ast_string_field_set(trunk, device, dev);
06757 
06758    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06759       if (!strcasecmp(var->name, "autocontext"))
06760          ast_string_field_set(trunk, autocontext, var->value);
06761       else if (!strcasecmp(var->name, "ringtimeout")) {
06762          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
06763             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
06764                var->value, trunk->name);
06765             trunk->ring_timeout = 0;
06766          }
06767       } else if (!strcasecmp(var->name, "barge"))
06768          trunk->barge_disabled = ast_false(var->value);
06769       else if (!strcasecmp(var->name, "hold")) {
06770          if (!strcasecmp(var->value, "private"))
06771             trunk->hold_access = SLA_HOLD_PRIVATE;
06772          else if (!strcasecmp(var->value, "open"))
06773             trunk->hold_access = SLA_HOLD_OPEN;
06774          else {
06775             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
06776                var->value, trunk->name);
06777          }
06778       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06779          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06780             var->name, var->lineno, SLA_CONFIG_FILE);
06781       }
06782    }
06783 
06784    if (!ast_strlen_zero(trunk->autocontext)) {
06785       struct ast_context *context;
06786       context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
06787       if (!context) {
06788          ast_log(LOG_ERROR, "Failed to automatically find or create "
06789             "context '%s' for SLA!\n", trunk->autocontext);
06790          destroy_trunk(trunk);
06791          return -1;
06792       }
06793       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
06794          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
06795          ast_log(LOG_ERROR, "Failed to automatically create extension "
06796             "for trunk '%s'!\n", trunk->name);
06797          destroy_trunk(trunk);
06798          return -1;
06799       }
06800    }
06801 
06802    AST_RWLIST_WRLOCK(&sla_trunks);
06803    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
06804    AST_RWLIST_UNLOCK(&sla_trunks);
06805 
06806    return 0;
06807 }

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

05982 {
05983    struct sla_station *station;
05984    int res = 0;
05985 
05986    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05987       struct sla_ringing_trunk *ringing_trunk;
05988       int time_left;
05989 
05990       /* Ignore stations already ringing */
05991       if (sla_check_ringing_station(station))
05992          continue;
05993 
05994       /* Ignore stations already on a call */
05995       if (sla_check_inuse_station(station))
05996          continue;
05997 
05998       /* Ignore stations that don't have one of their trunks ringing */
05999       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
06000          continue;
06001 
06002       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
06003          continue;
06004 
06005       /* If there is no time left, then the station needs to start ringing.
06006        * Return non-zero so that an event will be queued up an event to 
06007        * make that happen. */
06008       if (time_left <= 0) {
06009          res = 1;
06010          continue;
06011       }
06012 
06013       if (time_left < *timeout)
06014          *timeout = time_left;
06015    }
06016 
06017    return res;
06018 }

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

05899 {
05900    struct sla_ringing_trunk *ringing_trunk;
05901    struct sla_ringing_station *ringing_station;
05902    int res = 0;
05903 
05904    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05905       unsigned int ring_timeout = 0;
05906       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
05907       struct sla_trunk_ref *trunk_ref;
05908 
05909       /* If there are any ring timeouts specified for a specific trunk
05910        * on the station, then use the highest per-trunk ring timeout.
05911        * Otherwise, use the ring timeout set for the entire station. */
05912       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05913          struct sla_station_ref *station_ref;
05914          int trunk_time_elapsed, trunk_time_left;
05915 
05916          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05917             if (ringing_trunk->trunk == trunk_ref->trunk)
05918                break;
05919          }
05920          if (!ringing_trunk)
05921             continue;
05922 
05923          /* If there is a trunk that is ringing without a timeout, then the
05924           * only timeout that could matter is a global station ring timeout. */
05925          if (!trunk_ref->ring_timeout)
05926             break;
05927 
05928          /* This trunk on this station is ringing and has a timeout.
05929           * However, make sure this trunk isn't still ringing from a
05930           * previous timeout.  If so, don't consider it. */
05931          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
05932             if (station_ref->station == ringing_station->station)
05933                break;
05934          }
05935          if (station_ref)
05936             continue;
05937 
05938          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05939          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
05940          if (trunk_time_left > final_trunk_time_left)
05941             final_trunk_time_left = trunk_time_left;
05942       }
05943 
05944       /* No timeout was found for ringing trunks, and no timeout for the entire station */
05945       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
05946          continue;
05947 
05948       /* Compute how much time is left for a global station timeout */
05949       if (ringing_station->station->ring_timeout) {
05950          ring_timeout = ringing_station->station->ring_timeout;
05951          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
05952          time_left = (ring_timeout * 1000) - time_elapsed;
05953       }
05954 
05955       /* If the time left based on the per-trunk timeouts is smaller than the
05956        * global station ring timeout, use that. */
05957       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
05958          time_left = final_trunk_time_left;
05959 
05960       /* If there is no time left, the station needs to stop ringing */
05961       if (time_left <= 0) {
05962          AST_LIST_REMOVE_CURRENT(entry);
05963          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
05964          res = 1;
05965          continue;
05966       }
05967 
05968       /* There is still some time left for this station to ring, so save that
05969        * timeout if it is the first event scheduled to occur */
05970       if (time_left < *timeout)
05971          *timeout = time_left;
05972    }
05973    AST_LIST_TRAVERSE_SAFE_END;
05974 
05975    return res;
05976 }

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

05869 {
05870    struct sla_ringing_trunk *ringing_trunk;
05871    int res = 0;
05872 
05873    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05874       int time_left, time_elapsed;
05875       if (!ringing_trunk->trunk->ring_timeout)
05876          continue;
05877       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05878       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
05879       if (time_left <= 0) {
05880          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
05881          AST_LIST_REMOVE_CURRENT(entry);
05882          sla_stop_ringing_trunk(ringing_trunk);
05883          res = 1;
05884          continue;
05885       }
05886       if (time_left < *timeout)
05887          *timeout = time_left;
05888    }
05889    AST_LIST_TRAVERSE_SAFE_END;
05890 
05891    return res;
05892 }

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

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

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

05339 {
05340    struct sla_station *station;
05341    struct sla_trunk_ref *trunk_ref;
05342 
05343    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05344       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05345          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
05346             || trunk_ref == exclude)
05347             continue;
05348          trunk_ref->state = state;
05349          ast_devstate_changed(sla_state_to_devstate(state), 
05350             "SLA:%s_%s", station->name, trunk->name);
05351          break;
05352       }
05353    }
05354 }

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

Definition at line 6721 of file app_meetme.c.

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

Referenced by sla_build_trunk().

06722 {
06723    char *tech, *tech_data;
06724 
06725    tech_data = ast_strdupa(device);
06726    tech = strsep(&tech_data, "/");
06727 
06728    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
06729       return -1;
06730 
06731    return 0;
06732 }

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

05618 {
05619    struct sla_failed_station *failed_station;
05620    int res = 0;
05621 
05622    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
05623       if (station != failed_station->station)
05624          continue;
05625       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
05626          AST_LIST_REMOVE_CURRENT(entry);
05627          ast_free(failed_station);
05628          break;
05629       }
05630       res = 1;
05631    }
05632    AST_LIST_TRAVERSE_SAFE_END
05633 
05634    return res;
05635 }

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

Check to see if a station is in use.

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

05703 {
05704    struct sla_trunk_ref *trunk_ref;
05705 
05706    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05707       if (trunk_ref->chan)
05708          return 1;
05709    }
05710 
05711    return 0;
05712 }

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

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

Referenced by sla_thread().

06061 {
06062    struct sla_station *station;
06063    struct sla_trunk *trunk;
06064 
06065    ast_mutex_lock(&sla.lock);
06066 
06067    if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
06068       || !AST_LIST_EMPTY(&sla.ringing_stations)) {
06069       ast_mutex_unlock(&sla.lock);
06070       return;
06071    }
06072 
06073    AST_RWLIST_RDLOCK(&sla_stations);
06074    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
06075       if (station->ref_count)
06076          break;
06077    }
06078    AST_RWLIST_UNLOCK(&sla_stations);
06079    if (station) {
06080       ast_mutex_unlock(&sla.lock);
06081       return;
06082    }
06083 
06084    AST_RWLIST_RDLOCK(&sla_trunks);
06085    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
06086       if (trunk->ref_count)
06087          break;
06088    }
06089    AST_RWLIST_UNLOCK(&sla_trunks);
06090    if (trunk) {
06091       ast_mutex_unlock(&sla.lock);
06092       return;
06093    }
06094 
06095    /* yay */
06096    sla_load_config(1);
06097    sla.reload = 0;
06098 
06099    ast_mutex_unlock(&sla.lock);
06100 }

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

05603 {
05604    struct sla_ringing_station *ringing_station;
05605 
05606    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
05607       if (station == ringing_station->station)
05608          return 1;
05609    }
05610 
05611    return 0;
05612 }

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

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

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

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

05734 {
05735    struct sla_trunk_ref *trunk_ref;
05736    unsigned int delay = UINT_MAX;
05737    int time_left, time_elapsed;
05738 
05739    if (!ringing_trunk)
05740       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
05741    else
05742       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
05743 
05744    if (!ringing_trunk || !trunk_ref)
05745       return delay;
05746 
05747    /* If this station has a ring delay specific to the highest priority
05748     * ringing trunk, use that.  Otherwise, use the ring delay specified
05749     * globally for the station. */
05750    delay = trunk_ref->ring_delay;
05751    if (!delay)
05752       delay = station->ring_delay;
05753    if (!delay)
05754       return INT_MAX;
05755 
05756    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05757    time_left = (delay * 1000) - time_elapsed;
05758 
05759    return time_left;
05760 }

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

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

05244 {
05245    struct sla_station_ref *station_ref;
05246    struct sla_trunk_ref *trunk_ref;
05247 
05248    /* For each station that has this call on hold, check for private hold. */
05249    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
05250       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
05251          if (trunk_ref->trunk != trunk || station_ref->station == station)
05252             continue;
05253          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
05254             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
05255             return 1;
05256          return 0;
05257       }
05258    }
05259 
05260    return 0;
05261 }

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

05475 {
05476    struct sla_station_ref *timed_out_station;
05477 
05478    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
05479       if (station == timed_out_station->station)
05480          return 1;
05481    }
05482 
05483    return 0;
05484 }

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

06285 {
06286    struct sla_trunk_ref *trunk_ref = NULL;
06287 
06288    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06289       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
06290          break;
06291    }
06292 
06293    return trunk_ref;
06294 }

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

Choose the highest priority ringing trunk for a station.

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

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

05496 {
05497    struct sla_trunk_ref *s_trunk_ref;
05498    struct sla_ringing_trunk *ringing_trunk = NULL;
05499 
05500    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
05501       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05502          /* Make sure this is the trunk we're looking for */
05503          if (s_trunk_ref->trunk != ringing_trunk->trunk)
05504             continue;
05505 
05506          /* This trunk on the station is ringing.  But, make sure this station
05507           * didn't already time out while this trunk was ringing. */
05508          if (sla_check_timed_out_station(ringing_trunk, station))
05509             continue;
05510 
05511          if (rm)
05512             AST_LIST_REMOVE_CURRENT(entry);
05513 
05514          if (trunk_ref)
05515             *trunk_ref = s_trunk_ref;
05516 
05517          break;
05518       }
05519       AST_LIST_TRAVERSE_SAFE_END;
05520    
05521       if (ringing_trunk)
05522          break;
05523    }
05524 
05525    return ringing_trunk;
05526 }

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

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

05308 {
05309    struct sla_ringing_station *ringing_station;
05310 
05311    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
05312       return NULL;
05313 
05314    ringing_station->station = station;
05315    ringing_station->ring_begin = ast_tvnow();
05316 
05317    return ringing_station;
05318 }

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

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

05296 {
05297    struct sla_station_ref *station_ref;
05298 
05299    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
05300       return NULL;
05301 
05302    station_ref->station = station;
05303 
05304    return station_ref;
05305 }

static void sla_destroy ( void   )  [static]

Definition at line 6691 of file app_meetme.c.

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

Referenced by unload_module().

06692 {
06693    struct sla_trunk *trunk;
06694    struct sla_station *station;
06695 
06696    AST_RWLIST_WRLOCK(&sla_trunks);
06697    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
06698       destroy_trunk(trunk);
06699    AST_RWLIST_UNLOCK(&sla_trunks);
06700 
06701    AST_RWLIST_WRLOCK(&sla_stations);
06702    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
06703       destroy_station(station);
06704    AST_RWLIST_UNLOCK(&sla_stations);
06705 
06706    if (sla.thread != AST_PTHREADT_NULL) {
06707       ast_mutex_lock(&sla.lock);
06708       sla.stop = 1;
06709       ast_cond_signal(&sla.cond);
06710       ast_mutex_unlock(&sla.lock);
06711       pthread_join(sla.thread, NULL);
06712    }
06713 
06714    /* Drop any created contexts from the dialplan */
06715    ast_context_destroy(NULL, sla_registrar);
06716 
06717    ast_mutex_destroy(&sla.lock);
06718    ast_cond_destroy(&sla.cond);
06719 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 5465 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

05466 {
05467    sla_queue_event(SLA_EVENT_DIAL_STATE);
05468 }

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

References AST_RWLIST_TRAVERSE, and sla_station::name.

Referenced by sla_station_exec().

05231 {
05232    struct sla_station *station = NULL;
05233 
05234    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
05235       if (!strcasecmp(station->name, name))
05236          break;
05237    }
05238 
05239    return station;
05240 }

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

References AST_RWLIST_TRAVERSE, and sla_trunk::name.

Referenced by sla_trunk_exec().

05216 {
05217    struct sla_trunk *trunk = NULL;
05218 
05219    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05220       if (!strcasecmp(trunk->name, name))
05221          break;
05222    }
05223 
05224    return trunk;
05225 }

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

Definition at line 5714 of file app_meetme.c.

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

Referenced by sla_check_station_delay().

05716 {
05717    struct sla_trunk_ref *trunk_ref = NULL;
05718 
05719    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05720       if (trunk_ref->trunk == trunk)
05721          break;
05722    }
05723 
05724    return trunk_ref;
05725 }

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

Find a trunk reference on a station by name.

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

Definition at line 5270 of file app_meetme.c.

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

Referenced by sla_station_exec().

05272 {
05273    struct sla_trunk_ref *trunk_ref = NULL;
05274 
05275    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05276       if (strcasecmp(trunk_ref->trunk->name, name))
05277          continue;
05278 
05279       if ( (trunk_ref->trunk->barge_disabled 
05280          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
05281          (trunk_ref->trunk->hold_stations 
05282          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
05283          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
05284          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
05285       {
05286          trunk_ref = NULL;
05287       }
05288 
05289       break;
05290    }
05291 
05292    return trunk_ref;
05293 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 5528 of file app_meetme.c.

References ALL_TRUNK_REFS, answer_trunk_chan(), ast_cond_destroy, ast_cond_init, ast_cond_wait, ast_debug, ast_dial_answered(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_state(), ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_destroy, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_detached_background, sla_trunk::chan, sla_trunk_ref::chan, run_station_args::cond, run_station_args::cond_lock, sla_station::dial, sla_station::name, run_station(), sla, sla_change_trunk_state(), sla_choose_ringing_trunk(), SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_queue_event(), SLA_STATION_HANGUP_NORMAL, sla_stop_ringing_station(), SLA_TRUNK_STATE_UP, run_station_args::station, sla_ringing_station::station, sla_ringing_trunk::trunk, and run_station_args::trunk_ref.

Referenced by sla_thread().

05529 {
05530    struct sla_ringing_station *ringing_station;
05531 
05532    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05533       struct sla_trunk_ref *s_trunk_ref = NULL;
05534       struct sla_ringing_trunk *ringing_trunk = NULL;
05535       struct run_station_args args;
05536       enum ast_dial_result dial_res;
05537       pthread_t dont_care;
05538       ast_mutex_t cond_lock;
05539       ast_cond_t cond;
05540 
05541       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
05542       case AST_DIAL_RESULT_HANGUP:
05543       case AST_DIAL_RESULT_INVALID:
05544       case AST_DIAL_RESULT_FAILED:
05545       case AST_DIAL_RESULT_TIMEOUT:
05546       case AST_DIAL_RESULT_UNANSWERED:
05547          AST_LIST_REMOVE_CURRENT(entry);
05548          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
05549          break;
05550       case AST_DIAL_RESULT_ANSWERED:
05551          AST_LIST_REMOVE_CURRENT(entry);
05552          /* Find the appropriate trunk to answer. */
05553          ast_mutex_lock(&sla.lock);
05554          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
05555          ast_mutex_unlock(&sla.lock);
05556          if (!ringing_trunk) {
05557             ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
05558             break;
05559          }
05560          /* Track the channel that answered this trunk */
05561          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
05562          /* Actually answer the trunk */
05563          answer_trunk_chan(ringing_trunk->trunk->chan);
05564          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05565          /* Now, start a thread that will connect this station to the trunk.  The rest of
05566           * the code here sets up the thread and ensures that it is able to save the arguments
05567           * before they are no longer valid since they are allocated on the stack. */
05568          args.trunk_ref = s_trunk_ref;
05569          args.station = ringing_station->station;
05570          args.cond = &cond;
05571          args.cond_lock = &cond_lock;
05572          ast_free(ringing_trunk);
05573          ast_free(ringing_station);
05574          ast_mutex_init(&cond_lock);
05575          ast_cond_init(&cond, NULL);
05576          ast_mutex_lock(&cond_lock);
05577          ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
05578          ast_cond_wait(&cond, &cond_lock);
05579          ast_mutex_unlock(&cond_lock);
05580          ast_mutex_destroy(&cond_lock);
05581          ast_cond_destroy(&cond);
05582          break;
05583       case AST_DIAL_RESULT_TRYING:
05584       case AST_DIAL_RESULT_RINGING:
05585       case AST_DIAL_RESULT_PROGRESS:
05586       case AST_DIAL_RESULT_PROCEEDING:
05587          break;
05588       }
05589       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
05590          /* Queue up reprocessing ringing trunks, and then ringing stations again */
05591          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05592          sla_queue_event(SLA_EVENT_DIAL_STATE);
05593          break;
05594       }
05595    }
05596    AST_LIST_TRAVERSE_SAFE_END;
05597 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 5844 of file app_meetme.c.

References sla_trunk::active_stations, ast_atomic_fetchadd_int(), AST_CONTROL_HOLD, AST_DEVICE_ONHOLD, ast_devstate_changed(), ast_indicate(), ast_softhangup(), AST_SOFTHANGUP_DEV, sla_trunk_ref::chan, sla_trunk::chan, sla_trunk::hold_stations, INACTIVE_TRUNK_REFS, sla_trunk::name, sla_station::name, sla_change_trunk_state(), SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, sla_event::station, sla_trunk_ref::trunk, and sla_event::trunk_ref.

Referenced by sla_thread().

05845 {
05846    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
05847    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
05848    ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
05849       event->station->name, event->trunk_ref->trunk->name);
05850    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
05851       INACTIVE_TRUNK_REFS, event->trunk_ref);
05852 
05853    if (event->trunk_ref->trunk->active_stations == 1) {
05854       /* The station putting it on hold is the only one on the call, so start
05855        * Music on hold to the trunk. */
05856       event->trunk_ref->trunk->on_hold = 1;
05857       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
05858    }
05859 
05860    ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
05861    event->trunk_ref->chan = NULL;
05862 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 5834 of file app_meetme.c.

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

Referenced by sla_thread().

05835 {
05836    ast_mutex_lock(&sla.lock);
05837    sla_ring_stations();
05838    ast_mutex_unlock(&sla.lock);
05839 
05840    /* Find stations that shouldn't be ringing anymore. */
05841    sla_hangup_stations();
05842 }

static void sla_hangup_stations ( void   )  [static]

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

05807 {
05808    struct sla_trunk_ref *trunk_ref;
05809    struct sla_ringing_station *ringing_station;
05810 
05811    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05812       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05813          struct sla_ringing_trunk *ringing_trunk;
05814          ast_mutex_lock(&sla.lock);
05815          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05816             if (trunk_ref->trunk == ringing_trunk->trunk)
05817                break;
05818          }
05819          ast_mutex_unlock(&sla.lock);
05820          if (ringing_trunk)
05821             break;
05822       }
05823       if (!trunk_ref) {
05824          AST_LIST_REMOVE_CURRENT(entry);
05825          ast_dial_join(ringing_station->station->dial);
05826          ast_dial_destroy(ringing_station->station->dial);
05827          ringing_station->station->dial = NULL;
05828          ast_free(ringing_station);
05829       }
05830    }
05831    AST_LIST_TRAVERSE_SAFE_END
05832 }

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

Definition at line 1645 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01646 {
01647    const char *hold = "Unknown";
01648 
01649    switch (hold_access) {
01650    case SLA_HOLD_OPEN:
01651       hold = "Open";
01652       break;
01653    case SLA_HOLD_PRIVATE:
01654       hold = "Private";
01655    default:
01656       break;
01657    }
01658 
01659    return hold;
01660 }

static int sla_load_config ( int  reload  )  [static]

Definition at line 6971 of file app_meetme.c.

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

Referenced by load_config(), and sla_check_reload().

06972 {
06973    struct ast_config *cfg;
06974    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06975    const char *cat = NULL;
06976    int res = 0;
06977    const char *val;
06978 
06979    if (!reload) {
06980       ast_mutex_init(&sla.lock);
06981       ast_cond_init(&sla.cond, NULL);
06982    }
06983 
06984    if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
06985       return 0; /* Treat no config as normal */
06986    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06987       return 0;
06988    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06989       ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format.  Aborting.\n");
06990       return 0;
06991    }
06992 
06993    if (reload) {
06994       struct sla_station *station;
06995       struct sla_trunk *trunk;
06996 
06997       /* We need to actually delete the previous versions of trunks and stations now */
06998       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_stations, station, entry) {
06999          AST_RWLIST_REMOVE_CURRENT(entry);
07000          ast_free(station);
07001       }
07002       AST_RWLIST_TRAVERSE_SAFE_END;
07003 
07004       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_trunks, trunk, entry) {
07005          AST_RWLIST_REMOVE_CURRENT(entry);
07006          ast_free(trunk);
07007       }
07008       AST_RWLIST_TRAVERSE_SAFE_END;
07009    }
07010 
07011    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
07012       sla.attempt_callerid = ast_true(val);
07013 
07014    while ((cat = ast_category_browse(cfg, cat)) && !res) {
07015       const char *type;
07016       if (!strcasecmp(cat, "general"))
07017          continue;
07018       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
07019          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
07020             SLA_CONFIG_FILE);
07021          continue;
07022       }
07023       if (!strcasecmp(type, "trunk"))
07024          res = sla_build_trunk(cfg, cat);
07025       else if (!strcasecmp(type, "station"))
07026          res = sla_build_station(cfg, cat);
07027       else {
07028          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
07029             SLA_CONFIG_FILE, type);
07030       }
07031    }
07032 
07033    ast_config_destroy(cfg);
07034 
07035    /* Even if we don't have any stations, we may after a reload and we need to
07036     * be able to process the SLA_EVENT_RELOAD event in that case */
07037    if (sla.thread == AST_PTHREADT_NULL && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_trunks))) {
07038       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
07039    }
07040 
07041    return res;
07042 }

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

06023 {
06024    unsigned int timeout = UINT_MAX;
06025    struct timeval wait;
06026    unsigned int change_made = 0;
06027 
06028    /* Check for ring timeouts on ringing trunks */
06029    if (sla_calc_trunk_timeouts(&timeout))
06030       change_made = 1;
06031 
06032    /* Check for ring timeouts on ringing stations */
06033    if (sla_calc_station_timeouts(&timeout))
06034       change_made = 1;
06035 
06036    /* Check for station ring delays */
06037    if (sla_calc_station_delays(&timeout))
06038       change_made = 1;
06039 
06040    /* queue reprocessing of ringing trunks */
06041    if (change_made)
06042       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
06043 
06044    /* No timeout */
06045    if (timeout == UINT_MAX)
06046       return 0;
06047 
06048    if (ts) {
06049       wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
06050       ts->tv_sec = wait.tv_sec;
06051       ts->tv_nsec = wait.tv_usec * 1000;
06052    }
06053 
06054    return 1;
06055 }

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

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

Referenced by conf_run().

01971 {
01972    struct sla_station *station;
01973    struct sla_trunk_ref *trunk_ref = NULL;
01974    char *trunk_name;
01975 
01976    trunk_name = ast_strdupa(conf->confno);
01977    strsep(&trunk_name, "_");
01978    if (ast_strlen_zero(trunk_name)) {
01979       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01980       return;
01981    }
01982 
01983    AST_RWLIST_RDLOCK(&sla_stations);
01984    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01985       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01986          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01987             break;
01988       }
01989       if (trunk_ref)
01990          break;
01991    }
01992    AST_RWLIST_UNLOCK(&sla_stations);
01993 
01994    if (!trunk_ref) {
01995       ast_debug(1, "Trunk not found for event!\n");
01996       return;
01997    }
01998 
01999    sla_queue_event_full(type, trunk_ref, station, 1);
02000 }

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

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

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

01933 {
01934    struct sla_event *event;
01935 
01936    if (sla.thread == AST_PTHREADT_NULL) {
01937       return;
01938    }
01939 
01940    if (!(event = ast_calloc(1, sizeof(*event))))
01941       return;
01942 
01943    event->type = type;
01944    event->trunk_ref = trunk_ref;
01945    event->station = station;
01946 
01947    if (!lock) {
01948       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01949       return;
01950    }
01951 
01952    ast_mutex_lock(&sla.lock);
01953    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01954    ast_cond_signal(&sla.cond);
01955    ast_mutex_unlock(&sla.lock);
01956 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1958 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01959 {
01960    sla_queue_event_full(type, NULL, NULL, 0);
01961 }

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

References ast_calloc, ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_TRYING, ast_dial_run(), ast_dial_set_state_callback(), AST_LIST_INSERT_HEAD, ast_party_caller_free(), ast_party_caller_init(), ast_strdupa, ast_tvnow(), ast_channel::caller, sla_trunk::chan, sla_station::device, sla_station::dial, sla_failed_station::last_try, sla, sla_create_ringing_station(), sla_dial_state_callback(), sla_failed_station::station, strsep(), and sla_ringing_trunk::trunk.

Referenced by sla_ring_stations().

05641 {
05642    char *tech, *tech_data;
05643    struct ast_dial *dial;
05644    struct sla_ringing_station *ringing_station;
05645    enum ast_dial_result res;
05646    int caller_is_saved;
05647    struct ast_party_caller caller;
05648 
05649    if (!(dial = ast_dial_create()))
05650       return -1;
05651 
05652    ast_dial_set_state_callback(dial, sla_dial_state_callback);
05653    tech_data = ast_strdupa(station->device);
05654    tech = strsep(&tech_data, "/");
05655 
05656    if (ast_dial_append(dial, tech, tech_data) == -1) {
05657       ast_dial_destroy(dial);
05658       return -1;
05659    }
05660 
05661    /* Do we need to save off the caller ID data? */
05662    caller_is_saved = 0;
05663    if (!sla.attempt_callerid) {
05664       caller_is_saved = 1;
05665       caller = ringing_trunk->trunk->chan->caller;
05666       ast_party_caller_init(&ringing_trunk->trunk->chan->caller);
05667    }
05668 
05669    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
05670    
05671    /* Restore saved caller ID */
05672    if (caller_is_saved) {
05673       ast_party_caller_free(&ringing_trunk->trunk->chan->caller);
05674       ringing_trunk->trunk->chan->caller = caller;
05675    }
05676    
05677    if (res != AST_DIAL_RESULT_TRYING) {
05678       struct sla_failed_station *failed_station;
05679       ast_dial_destroy(dial);
05680       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
05681          return -1;
05682       failed_station->station = station;
05683       failed_station->last_try = ast_tvnow();
05684       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
05685       return -1;
05686    }
05687    if (!(ringing_station = sla_create_ringing_station(station))) {
05688       ast_dial_join(dial);
05689       ast_dial_destroy(dial);
05690       return -1;
05691    }
05692 
05693    station->dial = dial;
05694 
05695    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
05696 
05697    return 0;
05698 }

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

05766 {
05767    struct sla_station_ref *station_ref;
05768    struct sla_ringing_trunk *ringing_trunk;
05769 
05770    /* Make sure that every station that uses at least one of the ringing
05771     * trunks, is ringing. */
05772    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05773       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
05774          int time_left;
05775 
05776          /* Is this station already ringing? */
05777          if (sla_check_ringing_station(station_ref->station))
05778             continue;
05779 
05780          /* Is this station already in a call? */
05781          if (sla_check_inuse_station(station_ref->station))
05782             continue;
05783 
05784          /* Did we fail to dial this station earlier?  If so, has it been
05785           * a minute since we tried? */
05786          if (sla_check_failed_station(station_ref->station))
05787             continue;
05788 
05789          /* If this station already timed out while this trunk was ringing,
05790           * do not dial it again for this ringing trunk. */
05791          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
05792             continue;
05793 
05794          /* Check for a ring delay in progress */
05795          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
05796          if (time_left != INT_MAX && time_left > 0)
05797             continue;
05798 
05799          /* It is time to make this station begin to ring.  Do it! */
05800          sla_ring_station(ringing_trunk, station_ref->station);
05801       }
05802    }
05803    /* Now, all of the stations that should be ringing, are ringing. */
05804 }

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

Definition at line 1727 of file app_meetme.c.

References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, sla_station::autocontext, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, sla_station::device, ast_cli_args::fd, sla_station::hold_access, sla_trunk::name, sla_station::name, sla_trunk_ref::ring_delay, sla_station::ring_delay, sla_trunk_ref::ring_timeout, sla_station::ring_timeout, S_OR, sla_hold_str(), sla_trunk_ref::state, sla_trunk_ref::trunk, sla_station::trunks, trunkstate2str(), and ast_cli_entry::usage.

01728 {
01729    const struct sla_station *station;
01730 
01731    switch (cmd) {
01732    case CLI_INIT:
01733       e->command = "sla show stations";
01734       e->usage =
01735          "Usage: sla show stations\n"
01736          "       This will list all stations defined in sla.conf\n";
01737       return NULL;
01738    case CLI_GENERATE:
01739       return NULL;
01740    }
01741 
01742    ast_cli(a->fd, "\n" 
01743                "=============================================================\n"
01744                "=== Configured SLA Stations =================================\n"
01745                "=============================================================\n"
01746                "===\n");
01747    AST_RWLIST_RDLOCK(&sla_stations);
01748    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01749       struct sla_trunk_ref *trunk_ref;
01750       char ring_timeout[16] = "(none)";
01751       char ring_delay[16] = "(none)";
01752       if (station->ring_timeout) {
01753          snprintf(ring_timeout, sizeof(ring_timeout), 
01754             "%u", station->ring_timeout);
01755       }
01756       if (station->ring_delay) {
01757          snprintf(ring_delay, sizeof(ring_delay), 
01758             "%u", station->ring_delay);
01759       }
01760       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01761                   "=== Station Name:    %s\n"
01762                   "=== ==> Device:      %s\n"
01763                   "=== ==> AutoContext: %s\n"
01764                   "=== ==> RingTimeout: %s\n"
01765                   "=== ==> RingDelay:   %s\n"
01766                   "=== ==> HoldAccess:  %s\n"
01767                   "=== ==> Trunks ...\n",
01768                   station->name, station->device,
01769                   S_OR(station->autocontext, "(none)"), 
01770                   ring_timeout, ring_delay,
01771                   sla_hold_str(station->hold_access));
01772       AST_RWLIST_RDLOCK(&sla_trunks);
01773       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01774          if (trunk_ref->ring_timeout) {
01775             snprintf(ring_timeout, sizeof(ring_timeout),
01776                "%u", trunk_ref->ring_timeout);
01777          } else
01778             strcpy(ring_timeout, "(none)");
01779          if (trunk_ref->ring_delay) {
01780             snprintf(ring_delay, sizeof(ring_delay),
01781                "%u", trunk_ref->ring_delay);
01782          } else
01783             strcpy(ring_delay, "(none)");
01784             ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
01785                      "===       ==> State:       %s\n"
01786                      "===       ==> RingTimeout: %s\n"
01787                      "===       ==> RingDelay:   %s\n",
01788                      trunk_ref->trunk->name,
01789                      trunkstate2str(trunk_ref->state),
01790                      ring_timeout, ring_delay);
01791       }
01792       AST_RWLIST_UNLOCK(&sla_trunks);
01793       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01794                   "===\n");
01795    }
01796    AST_RWLIST_UNLOCK(&sla_stations);
01797    ast_cli(a->fd, "============================================================\n"
01798                "\n");
01799 
01800    return CLI_SUCCESS;
01801 }

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

Definition at line 1662 of file app_meetme.c.

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

01663 {
01664    const struct sla_trunk *trunk;
01665 
01666    switch (cmd) {
01667    case CLI_INIT:
01668       e->command = "sla show trunks";
01669       e->usage =
01670          "Usage: sla show trunks\n"
01671          "       This will list all trunks defined in sla.conf\n";
01672       return NULL;
01673    case CLI_GENERATE:
01674       return NULL;
01675    }
01676 
01677    ast_cli(a->fd, "\n"
01678                "=============================================================\n"
01679                "=== Configured SLA Trunks ===================================\n"
01680                "=============================================================\n"
01681                "===\n");
01682    AST_RWLIST_RDLOCK(&sla_trunks);
01683    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01684       struct sla_station_ref *station_ref;
01685       char ring_timeout[16] = "(none)";
01686       if (trunk->ring_timeout)
01687          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01688       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01689                   "=== Trunk Name:       %s\n"
01690                   "=== ==> Device:       %s\n"
01691                   "=== ==> AutoContext:  %s\n"
01692                   "=== ==> RingTimeout:  %s\n"
01693                   "=== ==> BargeAllowed: %s\n"
01694                   "=== ==> HoldAccess:   %s\n"
01695                   "=== ==> Stations ...\n",
01696                   trunk->name, trunk->device, 
01697                   S_OR(trunk->autocontext, "(none)"), 
01698                   ring_timeout,
01699                   trunk->barge_disabled ? "No" : "Yes",
01700                   sla_hold_str(trunk->hold_access));
01701       AST_RWLIST_RDLOCK(&sla_stations);
01702       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01703          ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
01704       AST_RWLIST_UNLOCK(&sla_stations);
01705       ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
01706    }
01707    AST_RWLIST_UNLOCK(&sla_trunks);
01708    ast_cli(a->fd, "=============================================================\n\n");
01709 
01710    return CLI_SUCCESS;
01711 }

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

Definition at line 6615 of file app_meetme.c.

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

Referenced by load_module().

06616 {
06617    char *buf, *station_name, *trunk_name;
06618    struct sla_station *station;
06619    struct sla_trunk_ref *trunk_ref;
06620    enum ast_device_state res = AST_DEVICE_INVALID;
06621 
06622    trunk_name = buf = ast_strdupa(data);
06623    station_name = strsep(&trunk_name, "_");
06624 
06625    AST_RWLIST_RDLOCK(&sla_stations);
06626    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
06627       if (strcasecmp(station_name, station->name))
06628          continue;
06629       AST_RWLIST_RDLOCK(&sla_trunks);
06630       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06631          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
06632             break;
06633       }
06634       if (!trunk_ref) {
06635          AST_RWLIST_UNLOCK(&sla_trunks);
06636          break;
06637       }
06638       res = sla_state_to_devstate(trunk_ref->state);
06639       AST_RWLIST_UNLOCK(&sla_trunks);
06640    }
06641    AST_RWLIST_UNLOCK(&sla_stations);
06642 
06643    if (res == AST_DEVICE_INVALID) {
06644       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
06645          trunk_name, station_name);
06646    }
06647 
06648    return res;
06649 }

static enum ast_device_state sla_state_to_devstate ( enum sla_trunk_state  state  )  [static]

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

Definition at line 6296 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_flag64, ast_strdupa, ast_strlen_zero(), build_conf(), sla_trunk_ref::chan, sla_trunk::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dial_trunk(), dispose_conf(), free, sla_trunk::hold_stations, LOG_NOTICE, LOG_WARNING, MAX_CONFNUM, sla_trunk::name, sla_station::name, sla_trunk::on_hold, pbx_builtin_setvar_helper(), sla_station::ref_count, sla, sla_change_trunk_state(), sla_choose_idle_trunk(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_find_station(), sla_find_trunk_ref_byname(), sla_queue_event(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, sla_trunk_ref::state, strsep(), sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.

Referenced by load_module().

06297 {
06298    char *station_name, *trunk_name;
06299    struct sla_station *station;
06300    struct sla_trunk_ref *trunk_ref = NULL;
06301    char conf_name[MAX_CONFNUM];
06302    struct ast_flags64 conf_flags = { 0 };
06303    struct ast_conference *conf;
06304 
06305    if (ast_strlen_zero(data)) {
06306       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
06307       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06308       return 0;
06309    }
06310 
06311    trunk_name = ast_strdupa(data);
06312    station_name = strsep(&trunk_name, "_");
06313 
06314    if (ast_strlen_zero(station_name)) {
06315       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
06316       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06317       return 0;
06318    }
06319 
06320    AST_RWLIST_RDLOCK(&sla_stations);
06321    station = sla_find_station(station_name);
06322    if (station)
06323       ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
06324    AST_RWLIST_UNLOCK(&sla_stations);
06325 
06326    if (!station) {
06327       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
06328       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06329       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06330       return 0;
06331    }
06332 
06333    AST_RWLIST_RDLOCK(&sla_trunks);
06334    if (!ast_strlen_zero(trunk_name)) {
06335       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
06336    } else
06337       trunk_ref = sla_choose_idle_trunk(station);
06338    AST_RWLIST_UNLOCK(&sla_trunks);
06339 
06340    if (!trunk_ref) {
06341       if (ast_strlen_zero(trunk_name))
06342          ast_log(LOG_NOTICE, "No trunks available for call.\n");
06343       else {
06344          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
06345             "'%s' due to access controls.\n", trunk_name);
06346       }
06347       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
06348       ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06349       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06350       return 0;
06351    }
06352 
06353    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
06354       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
06355          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06356       else {
06357          trunk_ref->state = SLA_TRUNK_STATE_UP;
06358          ast_devstate_changed(AST_DEVICE_INUSE, 
06359             "SLA:%s_%s", station->name, trunk_ref->trunk->name);
06360       }
06361    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
06362       struct sla_ringing_trunk *ringing_trunk;
06363 
06364       ast_mutex_lock(&sla.lock);
06365       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
06366          if (ringing_trunk->trunk == trunk_ref->trunk) {
06367             AST_LIST_REMOVE_CURRENT(entry);
06368             break;
06369          }
06370       }
06371       AST_LIST_TRAVERSE_SAFE_END
06372       ast_mutex_unlock(&sla.lock);
06373 
06374       if (ringing_trunk) {
06375          answer_trunk_chan(ringing_trunk->trunk->chan);
06376          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06377 
06378          free(ringing_trunk);
06379 
06380          /* Queue up reprocessing ringing trunks, and then ringing stations again */
06381          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06382          sla_queue_event(SLA_EVENT_DIAL_STATE);
06383       }
06384    }
06385 
06386    trunk_ref->chan = chan;
06387 
06388    if (!trunk_ref->trunk->chan) {
06389       ast_mutex_t cond_lock;
06390       ast_cond_t cond;
06391       pthread_t dont_care;
06392       struct dial_trunk_args args = {
06393          .trunk_ref = trunk_ref,
06394          .station = station,
06395          .cond_lock = &cond_lock,
06396          .cond = &cond,
06397       };
06398       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06399       /* Create a thread to dial the trunk and dump it into the conference.
06400        * However, we want to wait until the trunk has been dialed and the
06401        * conference is created before continuing on here. */
06402       ast_autoservice_start(chan);
06403       ast_mutex_init(&cond_lock);
06404       ast_cond_init(&cond, NULL);
06405       ast_mutex_lock(&cond_lock);
06406       ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
06407       ast_cond_wait(&cond, &cond_lock);
06408       ast_mutex_unlock(&cond_lock);
06409       ast_mutex_destroy(&cond_lock);
06410       ast_cond_destroy(&cond);
06411       ast_autoservice_stop(chan);
06412       if (!trunk_ref->trunk->chan) {
06413          ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
06414          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
06415          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06416          trunk_ref->chan = NULL;
06417          ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06418          sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06419          return 0;
06420       }
06421    }
06422 
06423    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
06424       trunk_ref->trunk->on_hold) {
06425       trunk_ref->trunk->on_hold = 0;
06426       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
06427       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06428    }
06429 
06430    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
06431    ast_set_flag64(&conf_flags,
06432       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
06433    ast_answer(chan);
06434    conf = build_conf(conf_name, "", "", 0, 0, 1, chan, NULL);
06435    if (conf) {
06436       conf_run(chan, conf, &conf_flags, NULL);
06437       dispose_conf(conf);
06438       conf = NULL;
06439    }
06440    trunk_ref->chan = NULL;
06441    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
06442       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
06443       strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
06444       admin_exec(NULL, conf_name);
06445       trunk_ref->trunk->hold_stations = 0;
06446       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06447    }
06448    
06449    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
06450 
06451    ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06452    sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06453 
06454    return 0;
06455 }

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

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

05432 {
05433    struct sla_ringing_trunk *ringing_trunk;
05434    struct sla_trunk_ref *trunk_ref;
05435    struct sla_station_ref *station_ref;
05436 
05437    ast_dial_join(ringing_station->station->dial);
05438    ast_dial_destroy(ringing_station->station->dial);
05439    ringing_station->station->dial = NULL;
05440 
05441    if (hangup == SLA_STATION_HANGUP_NORMAL)
05442       goto done;
05443 
05444    /* If the station is being hung up because of a timeout, then add it to the
05445     * list of timed out stations on each of the ringing trunks.  This is so
05446     * that when doing further processing to figure out which stations should be
05447     * ringing, which trunk to answer, determining timeouts, etc., we know which
05448     * ringing trunks we should ignore. */
05449    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05450       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05451          if (ringing_trunk->trunk == trunk_ref->trunk)
05452             break;
05453       }
05454       if (!trunk_ref)
05455          continue;
05456       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
05457          continue;
05458       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
05459    }
05460 
05461 done:
05462    ast_free(ringing_station);
05463 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 5415 of file app_meetme.c.

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

Referenced by sla_calc_trunk_timeouts().

05416 {
05417    char buf[80];
05418    struct sla_station_ref *station_ref;
05419 
05420    snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
05421    admin_exec(NULL, buf);
05422    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05423 
05424    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
05425       ast_free(station_ref);
05426 
05427    ast_free(ringing_trunk);
05428 }

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

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

06103 {
06104    struct sla_failed_station *failed_station;
06105    struct sla_ringing_station *ringing_station;
06106 
06107    ast_mutex_lock(&sla.lock);
06108 
06109    while (!sla.stop) {
06110       struct sla_event *event;
06111       struct timespec ts = { 0, };
06112       unsigned int have_timeout = 0;
06113 
06114       if (AST_LIST_EMPTY(&sla.event_q)) {
06115          if ((have_timeout = sla_process_timers(&ts)))
06116             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
06117          else
06118             ast_cond_wait(&sla.cond, &sla.lock);
06119          if (sla.stop)
06120             break;
06121       }
06122 
06123       if (have_timeout)
06124          sla_process_timers(NULL);
06125 
06126       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
06127          ast_mutex_unlock(&sla.lock);
06128          switch (event->type) {
06129          case SLA_EVENT_HOLD:
06130             sla_handle_hold_event(event);
06131             break;
06132          case SLA_EVENT_DIAL_STATE:
06133             sla_handle_dial_state_event();
06134             break;
06135          case SLA_EVENT_RINGING_TRUNK:
06136             sla_handle_ringing_trunk_event();
06137             break;
06138          case SLA_EVENT_RELOAD:
06139             sla.reload = 1;
06140          case SLA_EVENT_CHECK_RELOAD:
06141             break;
06142          }
06143          ast_free(event);
06144          ast_mutex_lock(&sla.lock);
06145       }
06146 
06147       if (sla.reload) {
06148          sla_check_reload();
06149       }
06150    }
06151 
06152    ast_mutex_unlock(&sla.lock);
06153 
06154    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
06155       ast_free(ringing_station);
06156 
06157    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
06158       ast_free(failed_station);
06159 
06160    return NULL;
06161 }

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

Definition at line 6503 of file app_meetme.c.

References ALL_TRUNK_REFS, args, AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_free, ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag64, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, build_conf(), sla_trunk::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, dispose_conf(), LOG_ERROR, MAX_CONFNUM, sla_trunk::on_hold, 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_MOH, sla_trunk_opts, SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by load_module().

06504 {
06505    char conf_name[MAX_CONFNUM];
06506    struct ast_conference *conf;
06507    struct ast_flags64 conf_flags = { 0 };
06508    struct sla_trunk *trunk;
06509    struct sla_ringing_trunk *ringing_trunk;
06510    AST_DECLARE_APP_ARGS(args,
06511       AST_APP_ARG(trunk_name);
06512       AST_APP_ARG(options);
06513    );
06514    char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
06515    struct ast_flags opt_flags = { 0 };
06516    char *parse;
06517 
06518    if (ast_strlen_zero(data)) {
06519       ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
06520       return -1;
06521    }
06522 
06523    parse = ast_strdupa(data);
06524    AST_STANDARD_APP_ARGS(args, parse);
06525    if (args.argc == 2) {
06526       if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
06527          ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
06528          return -1;
06529       }
06530    }
06531 
06532    AST_RWLIST_RDLOCK(&sla_trunks);
06533    trunk = sla_find_trunk(args.trunk_name);
06534    if (trunk)
06535       ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
06536    AST_RWLIST_UNLOCK(&sla_trunks);
06537 
06538    if (!trunk) {
06539       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
06540       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06541       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06542       return 0;
06543    }
06544 
06545    if (trunk->chan) {
06546       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
06547          args.trunk_name);
06548       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06549       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06550       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06551       return 0;
06552    }
06553 
06554    trunk->chan = chan;
06555 
06556    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
06557       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06558       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06559       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06560       return 0;
06561    }
06562 
06563    snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
06564    conf = build_conf(conf_name, "", "", 1, 1, 1, chan, NULL);
06565    if (!conf) {
06566       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06567       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06568       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06569       return 0;
06570    }
06571    ast_set_flag64(&conf_flags, 
06572       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
06573 
06574    if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
06575       ast_indicate(chan, -1);
06576       ast_set_flag64(&conf_flags, CONFFLAG_MOH);
06577    } else
06578       ast_indicate(chan, AST_CONTROL_RINGING);
06579 
06580    conf_run(chan, conf, &conf_flags, opts);
06581    dispose_conf(conf);
06582    conf = NULL;
06583    trunk->chan = NULL;
06584    trunk->on_hold = 0;
06585 
06586    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06587 
06588    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
06589       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
06590 
06591    /* Remove the entry from the list of ringing trunks if it is still there. */
06592    ast_mutex_lock(&sla.lock);
06593    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
06594       if (ringing_trunk->trunk == trunk) {
06595          AST_LIST_REMOVE_CURRENT(entry);
06596          break;
06597       }
06598    }
06599    AST_LIST_TRAVERSE_SAFE_END;
06600    ast_mutex_unlock(&sla.lock);
06601    if (ringing_trunk) {
06602       ast_free(ringing_trunk);
06603       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
06604       /* Queue reprocessing of ringing trunks to make stations stop ringing
06605        * that shouldn't be ringing after this trunk stopped. */
06606       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06607    }
06608 
06609    ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06610    sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06611 
06612    return 0;
06613 }

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

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

01714 {
01715 #define S(e) case e: return # e;
01716    switch (state) {
01717    S(SLA_TRUNK_STATE_IDLE)
01718    S(SLA_TRUNK_STATE_RINGING)
01719    S(SLA_TRUNK_STATE_UP)
01720    S(SLA_TRUNK_STATE_ONHOLD)
01721    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01722    }
01723    return "Uknown State";
01724 #undef S
01725 }

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

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

01125 {
01126    tweak_volume(&user->listen, action);
01127    /* attempt to make the adjustment in the channel driver;
01128       if successful, don't adjust in the frame reading routine
01129    */
01130    if (!set_listen_volume(user, user->listen.desired))
01131       user->listen.actual = 0;
01132    else
01133       user->listen.actual = user->listen.desired;
01134 }

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

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

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

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

Definition at line 1077 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

01078 {
01079    switch (action) {
01080    case VOL_UP:
01081       switch (vol->desired) { 
01082       case 5:
01083          break;
01084       case 0:
01085          vol->desired = 2;
01086          break;
01087       case -2:
01088          vol->desired = 0;
01089          break;
01090       default:
01091          vol->desired++;
01092          break;
01093       }
01094       break;
01095    case VOL_DOWN:
01096       switch (vol->desired) {
01097       case -5:
01098          break;
01099       case 2:
01100          vol->desired = 0;
01101          break;
01102       case 0:
01103          vol->desired = -2;
01104          break;
01105       default:
01106          vol->desired--;
01107          break;
01108       }
01109    }
01110 }

static int unload_module ( void   )  [static]

Definition at line 7311 of file app_meetme.c.

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

07312 {
07313    int res = 0;
07314    
07315    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07316    res = ast_manager_unregister("MeetmeMute");
07317    res |= ast_manager_unregister("MeetmeUnmute");
07318    res |= ast_manager_unregister("MeetmeList");
07319    res |= ast_manager_unregister("MeetmeListRooms");
07320    res |= ast_unregister_application(app4);
07321    res |= ast_unregister_application(app3);
07322    res |= ast_unregister_application(app2);
07323    res |= ast_unregister_application(app);
07324    res |= ast_unregister_application(slastation_app);
07325    res |= ast_unregister_application(slatrunk_app);
07326 
07327 #ifdef TEST_FRAMEWORK
07328    AST_TEST_UNREGISTER(test_meetme_data_provider);
07329 #endif
07330    ast_data_unregister(NULL);
07331 
07332    ast_devstate_prov_del("Meetme");
07333    ast_devstate_prov_del("SLA");
07334    
07335    sla_destroy();
07336    
07337    res |= ast_custom_function_unregister(&meetme_info_acf);
07338    ast_unload_realtime("meetme");
07339 
07340    return res;
07341 }

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

Definition at line 7162 of file app_meetme.c.

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

Referenced by meetme_data_provider_get().

07163 {
07164    struct ast_data *data_meetme_user;
07165    struct ast_data *data_meetme_user_channel;
07166    struct ast_data *data_meetme_user_volume;
07167 
07168    struct ast_conf_user *user = obj;
07169    struct ast_data *data_meetme_users = arg;
07170 
07171    data_meetme_user = ast_data_add_node(data_meetme_users, "user");
07172    if (!data_meetme_user) {
07173       return 0;
07174    }
07175    /* user structure */
07176    ast_data_add_structure(ast_conf_user, data_meetme_user, user);
07177 
07178    /* user's channel */
07179    data_meetme_user_channel = ast_data_add_node(data_meetme_user, "channel");
07180    if (!data_meetme_user_channel) {
07181       return 0;
07182    }
07183 
07184    ast_channel_data_add_structure(data_meetme_user_channel, user->chan, 1);
07185 
07186    /* volume structure */
07187    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "listen-volume");
07188    if (!data_meetme_user_volume) {
07189       return 0;
07190    }
07191    ast_data_add_int(data_meetme_user_volume, "desired", user->listen.desired);
07192    ast_data_add_int(data_meetme_user_volume, "actual", user->listen.actual);
07193 
07194    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "talk-volume");
07195    if (!data_meetme_user_volume) {
07196       return 0;
07197    }
07198    ast_data_add_int(data_meetme_user_volume, "desired", user->talk.desired);
07199    ast_data_add_int(data_meetme_user_volume, "actual", user->talk.actual);
07200 
07201    return 0;
07202 }

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

Definition at line 4626 of file app_meetme.c.

References ast_channel_name(), ast_conf_user::chan, CMP_MATCH, and CMP_STOP.

Referenced by channel_admin_exec().

04627 {
04628    struct ast_conf_user *user = obj;
04629    const char *channel = args;
04630 
04631    if (!strcmp(ast_channel_name(user->chan), channel)) {
04632       return (CMP_MATCH | CMP_STOP);
04633    }
04634 
04635    return 0;
04636 }

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

Definition at line 4598 of file app_meetme.c.

References tweak_listen_volume(), and VOL_DOWN.

Referenced by admin_exec().

04599 {
04600    struct ast_conf_user *user = obj;
04601    tweak_listen_volume(user, VOL_DOWN);
04602    return 0;
04603 }

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

Definition at line 4591 of file app_meetme.c.

References tweak_listen_volume(), and VOL_UP.

Referenced by admin_exec().

04592 {
04593    struct ast_conf_user *user = obj;
04594    tweak_listen_volume(user, VOL_UP);
04595    return 0;
04596 }

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

Definition at line 1190 of file app_meetme.c.

References ast_conf_user::user_no.

Referenced by admin_exec(), and conf_run().

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

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

Definition at line 1178 of file app_meetme.c.

References CMP_MATCH, CMP_STOP, and ast_conf_user::user_no.

Referenced by build_conf().

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

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

Definition at line 4619 of file app_meetme.c.

References reset_volumes().

Referenced by admin_exec().

04620 {
04621    struct ast_conf_user *user = obj;
04622    reset_volumes(user);
04623    return 0;
04624 }

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

Definition at line 2209 of file app_meetme.c.

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

Referenced by conf_run().

02210 {
02211    struct ast_conf_user *user = obj;
02212    /* actual pointer contents of check_admin_arg is irrelevant */
02213 
02214    if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
02215       user->adminflags |= ADMINFLAG_HANGUP;
02216    }
02217    return 0;
02218 }

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

Definition at line 2220 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

02221 {
02222    struct ast_conf_user *user = obj;
02223    /* actual pointer contents of check_admin_arg is irrelevant */
02224 
02225    if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
02226       user->adminflags |= ADMINFLAG_KICKME;
02227    }
02228    return 0;
02229 }

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

Definition at line 2242 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

02243 {
02244    struct ast_conf_user *user = obj;
02245    /* actual pointer contents of check_admin_arg is irrelevant */
02246 
02247    if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
02248       user->adminflags |= ADMINFLAG_MUTED;
02249    }
02250    return 0;
02251 }

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

Definition at line 2231 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

02232 {
02233    struct ast_conf_user *user = obj;
02234    /* actual pointer contents of check_admin_arg is irrelevant */
02235 
02236    if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
02237       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
02238    }
02239    return 0;
02240 }

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

Definition at line 4612 of file app_meetme.c.

References tweak_talk_volume(), and VOL_DOWN.

Referenced by admin_exec().

04613 {
04614    struct ast_conf_user *user = obj;
04615    tweak_talk_volume(user, VOL_DOWN);
04616    return 0;
04617 }

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

Definition at line 4605 of file app_meetme.c.

References tweak_talk_volume(), and VOL_UP.

Referenced by admin_exec().

04606 {
04607    struct ast_conf_user *user = obj;
04608    tweak_talk_volume(user, VOL_UP);
04609    return 0;
04610 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "MeetMe conference bridge" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, } [static]

Definition at line 7388 of file app_meetme.c.

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

Definition at line 696 of file app_meetme.c.

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

Definition at line 697 of file app_meetme.c.

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

Definition at line 698 of file app_meetme.c.

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

Definition at line 699 of file app_meetme.c.

Definition at line 7388 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 980 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 989 of file app_meetme.c.

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1803 of file app_meetme.c.

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

Definition at line 782 of file app_meetme.c.

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

int earlyalert [static]

Definition at line 706 of file app_meetme.c.

int endalert [static]

Definition at line 707 of file app_meetme.c.

struct { ... } event_q

int extendby [static]

Definition at line 708 of file app_meetme.c.

struct { ... } failed_stations

struct sla_event* first [read]

int fuzzystart [static]

Definition at line 705 of file app_meetme.c.

const char gain_map[] [static]

Map 'volume' levels from -5 through +5 into decibel (dB) settings for channel drivers.

Note:
these are not a straight linear-to-dB conversion... the numbers have been modified to give the user a better level of adjustability.

Definition at line 998 of file app_meetme.c.

struct sla_event* last [read]

Initial value:

Definition at line 7242 of file app_meetme.c.

Initial value:

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

Definition at line 7247 of file app_meetme.c.

Initial value:

 {
   .name = "MEETME_INFO",
   .read = acf_meetme_info,
}

Definition at line 7113 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 }, [ 'G' ] = { .flag = (1ULL << 32) , .arg_index = OPT_ARG_INTROMSG + 1 }, [ 'v' ] = { .flag = (1ULL << 33) , .arg_index = OPT_ARG_INTROUSER_VMREC + 1 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'k' ] = { .flag = ((uint64_t)1 << 34) }, [ '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 694 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 982 of file app_meetme.c.

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

struct { ... } ringing_stations

struct { ... } ringing_trunks

int rt_log_members [static]

Log participant count to the RealTime backend

Definition at line 711 of file app_meetme.c.

int rt_schedule [static]

Definition at line 704 of file app_meetme.c.

struct { ... } sla [static]

const char sla_registrar[] = "SLA" [static]

struct ast_app_option sla_trunk_opts[128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, } [static]

Definition at line 6501 of file app_meetme.c.

Referenced by sla_trunk_exec().

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

Definition at line 700 of file app_meetme.c.

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

Definition at line 701 of file app_meetme.c.

unsigned int stop

pthread_t thread


Generated on Sat Feb 11 06:33:48 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6