Mon Jun 27 16:50:58 2011

Asterisk developer's documentation


app_meetme.c File Reference

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

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

Go to the source code of this file.

Data Structures

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int acf_meetme_info (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_meetme_info_eval (const char *keyword, const struct ast_conference *conf)
static int action_meetmelist (struct mansession *s, const struct message *m)
static int action_meetmemute (struct mansession *s, const struct message *m)
static int action_meetmeunmute (struct mansession *s, const struct message *m)
static int admin_exec (struct ast_channel *chan, const char *data)
 The MeetMeadmin application.
static void * announce_thread (void *data)
static void answer_trunk_chan (struct ast_channel *chan)
 AST_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_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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 = ((uint64_t)1 << 32) , .arg_index = OPT_ARG_INTROMSG + 1 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
static int rt_log_members
static int rt_schedule
struct {
   unsigned int   attempt_callerid:1
   ast_cond_t   cond
   struct {
      sla_event *   first
      sla_event *   last
   }   event_q
   struct {
      sla_failed_station *   first
      sla_failed_station *   last
   }   failed_stations
   ast_mutex_t   lock
   unsigned int   reload:1
   struct {
      sla_ringing_station *   first
      sla_ringing_station *   last
   }   ringing_stations
   struct {
      sla_ringing_trunk *   first
      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 527 of file app_meetme.c.

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

#define CONF_SIZE   320

Definition at line 546 of file app_meetme.c.

#define CONFFLAG_INTROMSG   ((uint64_t)1 << 32)

Definition at line 610 of file app_meetme.c.

Referenced by conf_run().

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 507 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 514 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 511 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

Definition at line 672 of file app_meetme.c.

Referenced by conf_exec(), dial_trunk(), meetme_cmd(), meetme_show_cmd(), sla_station_exec(), and sla_trunk_exec().

#define MAX_PIN   80

Definition at line 673 of file app_meetme.c.

Referenced by conf_exec().

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

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

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 525 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 524 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_USER_DATA_EXPORT ( MEMBER   ) 

Definition at line 6915 of file app_meetme.c.

#define OPTIONS_LEN   100

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

Referenced by sla_load_config().


Enumeration Type Documentation

anonymous enum

Enumerator:
ADMINFLAG_MUTED  User is muted
ADMINFLAG_SELFMUTED  User muted self
ADMINFLAG_KICKME  User has been kicked
ADMINFLAG_T_REQUEST  User has requested to speak

Definition at line 516 of file app_meetme.c.

00516      {
00517    ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
00518    ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
00519    ADMINFLAG_KICKME =    (1 << 3),  /*!< User has been kicked */
00520    /*! User has requested to speak */
00521    ADMINFLAG_T_REQUEST = (1 << 4),
00522 };

anonymous enum

Enumerator:
CONFFLAG_ADMIN  user has admin access on the conference
CONFFLAG_MONITOR  If set the user can only receive audio from the conference
CONFFLAG_KEYEXIT  If set asterisk will exit conference when key defined in p() option is pressed
CONFFLAG_STARMENU  If set asterisk will provide a menu to the user when '*' is pressed
CONFFLAG_TALKER  If set the use can only send audio to the conference
CONFFLAG_QUIET  If set there will be no enter or leave sounds
CONFFLAG_ANNOUNCEUSERCOUNT  If set, when user joins the conference, they will be told the number of users that are already in
CONFFLAG_AGI  Set to run AGI Script in Background
CONFFLAG_MOH  Set to have music on hold when user is alone in conference
CONFFLAG_MARKEDEXIT  If set the MeetMe will return if all marked with this flag left
CONFFLAG_WAITMARKED  If set, the MeetMe will wait until a marked user enters
CONFFLAG_EXIT_CONTEXT  If set, the MeetMe will exit to the specified context
CONFFLAG_MARKEDUSER  If set, the user will be marked
CONFFLAG_INTROUSER  If set, user will be ask record name on entry of conference
CONFFLAG_RECORDCONF  If set, the MeetMe will be recorded
CONFFLAG_MONITORTALKER  If set, the user will be monitored if the user is talking or not
CONFFLAG_DYNAMIC 
CONFFLAG_DYNAMICPIN 
CONFFLAG_EMPTY 
CONFFLAG_EMPTYNOPIN 
CONFFLAG_ALWAYSPROMPT 
CONFFLAG_OPTIMIZETALKER  If set, treat talking users as muted users
CONFFLAG_NOONLYPERSON  If set, won't speak the extra prompt when the first person enters the conference
CONFFLAG_INTROUSERNOREVIEW  If set, user will be asked to record name on entry of conference without review
CONFFLAG_STARTMUTED  If set, the user will be initially self-muted
CONFFLAG_PASS_DTMF  Pass DTMF through the conference
CONFFLAG_SLA_STATION 
CONFFLAG_SLA_TRUNK 
CONFFLAG_KICK_CONTINUE  If set, the user should continue in the dialplan if kicked out
CONFFLAG_DURATION_STOP 
CONFFLAG_DURATION_LIMIT 
CONFFLAG_NO_AUDIO_UNTIL_UP  Do not write any audio to this channel until the state is up.

Definition at line 548 of file app_meetme.c.

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

anonymous enum

Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_EXITKEYS 
OPT_ARG_DURATION_STOP 
OPT_ARG_DURATION_LIMIT 
OPT_ARG_MOH_CLASS 
OPT_ARG_INTROMSG 
OPT_ARG_ARRAY_SIZE 

Definition at line 612 of file app_meetme.c.

00612      {
00613    OPT_ARG_WAITMARKED = 0,
00614    OPT_ARG_EXITKEYS   = 1,
00615    OPT_ARG_DURATION_STOP = 2,
00616    OPT_ARG_DURATION_LIMIT = 3,
00617    OPT_ARG_MOH_CLASS = 4,
00618    OPT_ARG_INTROMSG = 5,
00619    OPT_ARG_ARRAY_SIZE = 6,
00620 };

anonymous enum

Enumerator:
SLA_TRUNK_OPT_MOH 

Definition at line 6271 of file app_meetme.c.

06271      {
06272    SLA_TRUNK_OPT_MOH = (1 << 0),
06273 };

anonymous enum

Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 6275 of file app_meetme.c.

06275      {
06276    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
06277    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
06278 };

enum announcetypes

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 679 of file app_meetme.c.

00679                    {
00680    CONF_HASJOIN,
00681    CONF_HASLEFT
00682 };

enum entrance_sound

Enumerator:
ENTER 
LEAVE 

Definition at line 534 of file app_meetme.c.

00534                     {
00535    ENTER,
00536    LEAVE
00537 };

enum recording_state

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 539 of file app_meetme.c.

enum sla_event_type

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

00873                     {
00874    /*! A station has put the call on hold */
00875    SLA_EVENT_HOLD,
00876    /*! The state of a dial has changed */
00877    SLA_EVENT_DIAL_STATE,
00878    /*! The state of a ringing trunk has changed */
00879    SLA_EVENT_RINGING_TRUNK,
00880    /*! A reload of configuration has been requested */
00881    SLA_EVENT_RELOAD,
00882    /*! Poke the SLA thread so it can check if it can perform a reload */
00883    SLA_EVENT_CHECK_RELOAD,
00884 };

enum sla_hold_access

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

00783                      {
00784    /*! This means that any station can put it on hold, and any station
00785     * can retrieve the call from hold. */
00786    SLA_HOLD_OPEN,
00787    /*! This means that only the station that put the call on hold may
00788     * retrieve it from hold. */
00789    SLA_HOLD_PRIVATE,
00790 };

enum sla_station_hangup

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 910 of file app_meetme.c.

enum sla_trunk_state

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

enum sla_which_trunk_refs

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 770 of file app_meetme.c.

00770                           {
00771    ALL_TRUNK_REFS,
00772    INACTIVE_TRUNK_REFS,
00773 };

enum volume_action

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 529 of file app_meetme.c.

00529                    {
00530    VOL_UP,
00531    VOL_DOWN
00532 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 7151 of file app_meetme.c.

static void __unreg_module ( void   )  [static]

Definition at line 7151 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 6827 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_NOTICE, and parse().

06828 {
06829    struct ast_conference *conf;
06830    char *parse;
06831    int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
06832    AST_DECLARE_APP_ARGS(args,
06833       AST_APP_ARG(keyword);
06834       AST_APP_ARG(confno);
06835    );
06836 
06837    if (ast_strlen_zero(data)) {
06838       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
06839       return -1;
06840    }
06841 
06842    parse = ast_strdupa(data);
06843    AST_STANDARD_APP_ARGS(args, parse);
06844 
06845    if (ast_strlen_zero(args.keyword)) {
06846       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
06847       return -1;
06848    }
06849 
06850    if (ast_strlen_zero(args.confno)) {
06851       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
06852       return -1;
06853    }
06854 
06855    AST_LIST_LOCK(&confs);
06856    AST_LIST_TRAVERSE(&confs, conf, list) {
06857       if (!strcmp(args.confno, conf->confno)) {
06858          result = acf_meetme_info_eval(args.keyword, conf);
06859          break;
06860       }
06861    }
06862    AST_LIST_UNLOCK(&confs);
06863 
06864    if (result > -1) {
06865       snprintf(buf, len, "%d", result);
06866    } else if (result == -1) {
06867       ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
06868       snprintf(buf, len, "0");
06869    } else if (result == -2) {
06870       ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno); 
06871       snprintf(buf, len, "0");
06872    }
06873 
06874    return 0;
06875 }

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

Definition at line 6809 of file app_meetme.c.

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

Referenced by acf_meetme_info().

06810 {
06811    if (!strcasecmp("lock", keyword)) {
06812       return conf->locked;
06813    } else if (!strcasecmp("parties", keyword)) {
06814       return conf->users;
06815    } else if (!strcasecmp("activity", keyword)) {
06816       time_t now;
06817       now = time(NULL);
06818       return (now - conf->start);
06819    } else if (!strcasecmp("dynamic", keyword)) {
06820       return conf->isdynamic;
06821    } else {
06822       return -1;
06823    }
06824 
06825 }

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

Definition at line 4752 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag64, astman_append(), astman_get_header(), astman_send_error(), astman_send_listack(), CONFFLAG_ADMIN, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_conference::confno, S_COR, total, user, and ast_conference::usercontainer.

Referenced by load_module().

04753 {
04754    const char *actionid = astman_get_header(m, "ActionID");
04755    const char *conference = astman_get_header(m, "Conference");
04756    char idText[80] = "";
04757    struct ast_conference *cnf;
04758    struct ast_conf_user *user;
04759    struct ao2_iterator user_iter;
04760    int total = 0;
04761 
04762    if (!ast_strlen_zero(actionid))
04763       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04764 
04765    if (AST_LIST_EMPTY(&confs)) {
04766       astman_send_error(s, m, "No active conferences.");
04767       return 0;
04768    }
04769 
04770    astman_send_listack(s, m, "Meetme user list will follow", "start");
04771 
04772    /* Find the right conference */
04773    AST_LIST_LOCK(&confs);
04774    AST_LIST_TRAVERSE(&confs, cnf, list) {
04775       user_iter = ao2_iterator_init(cnf->usercontainer, 0);
04776       /* If we ask for one particular, and this isn't it, skip it */
04777       if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
04778          continue;
04779 
04780       /* Show all the users */
04781       while ((user = ao2_iterator_next(&user_iter))) {
04782          total++;
04783          astman_append(s,
04784             "Event: MeetmeList\r\n"
04785             "%s"
04786             "Conference: %s\r\n"
04787             "UserNumber: %d\r\n"
04788             "CallerIDNum: %s\r\n"
04789             "CallerIDName: %s\r\n"
04790             "Channel: %s\r\n"
04791             "Admin: %s\r\n"
04792             "Role: %s\r\n"
04793             "MarkedUser: %s\r\n"
04794             "Muted: %s\r\n"
04795             "Talking: %s\r\n"
04796             "\r\n",
04797             idText,
04798             cnf->confno,
04799             user->user_no,
04800             S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
04801             S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
04802             user->chan->name,
04803             ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
04804             ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
04805             ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
04806             user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
04807             user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
04808          ao2_ref(user, -1);
04809       }
04810       ao2_iterator_destroy(&user_iter);
04811    }
04812    AST_LIST_UNLOCK(&confs);
04813    /* Send final confirmation */
04814    astman_append(s,
04815    "Event: MeetmeListComplete\r\n"
04816    "EventList: Complete\r\n"
04817    "ListItems: %d\r\n"
04818    "%s"
04819    "\r\n", total, idText);
04820    return 0;
04821 }

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

Definition at line 4742 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04743 {
04744    return meetmemute(s, m, 1);
04745 }

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

Definition at line 4747 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04748 {
04749    return meetmemute(s, m, 0);
04750 }

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

The MeetMeadmin application.

MeetMeAdmin(confno, command, caller)

Definition at line 4480 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, 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, ast_conf_user::chan, 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, 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, and VOL_UP.

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

04480                                                                   {
04481    char *params;
04482    struct ast_conference *cnf;
04483    struct ast_conf_user *user = NULL;
04484    AST_DECLARE_APP_ARGS(args,
04485       AST_APP_ARG(confno);
04486       AST_APP_ARG(command);
04487       AST_APP_ARG(user);
04488    );
04489    int res = 0;
04490 
04491    if (ast_strlen_zero(data)) {
04492       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
04493       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04494       return -1;
04495    }
04496 
04497    params = ast_strdupa(data);
04498    AST_STANDARD_APP_ARGS(args, params);
04499 
04500    if (!args.command) {
04501       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
04502       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04503       return -1;
04504    }
04505 
04506    AST_LIST_LOCK(&confs);
04507    AST_LIST_TRAVERSE(&confs, cnf, list) {
04508       if (!strcmp(cnf->confno, args.confno))
04509          break;
04510    }
04511 
04512    if (!cnf) {
04513       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
04514       AST_LIST_UNLOCK(&confs);
04515       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
04516       return 0;
04517    }
04518 
04519    ast_atomic_fetchadd_int(&cnf->refcount, 1);
04520 
04521    if (args.user) {
04522       user = find_user(cnf, args.user);
04523       if (!user) {
04524          ast_log(LOG_NOTICE, "Specified User not found!\n");
04525          res = -2;
04526          goto usernotfound;
04527       }
04528    }
04529 
04530    switch (*args.command) {
04531    case 76: /* L: Lock */ 
04532       cnf->locked = 1;
04533       break;
04534    case 108: /* l: Unlock */ 
04535       cnf->locked = 0;
04536       break;
04537    case 75: /* K: kick all users */
04538       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_kickme_cb, NULL);
04539       break;
04540    case 101: /* e: Eject last user*/
04541    {
04542       int max_no = 0;
04543       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
04544       user = ao2_find(cnf->usercontainer, &max_no, 0);
04545       if (!ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))
04546          user->adminflags |= ADMINFLAG_KICKME;
04547       else {
04548          res = -1;
04549          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
04550       }
04551       ao2_ref(user, -1);
04552       break;
04553    }
04554    case 77: /* M: Mute */ 
04555       user->adminflags |= ADMINFLAG_MUTED;
04556       break;
04557    case 78: /* N: Mute all (non-admin) users */
04558       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_muted_cb, NULL);
04559       break;               
04560    case 109: /* m: Unmute */ 
04561       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04562       break;
04563    case 110: /* n: Unmute all users */
04564       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, NULL);
04565       break;
04566    case 107: /* k: Kick user */ 
04567       user->adminflags |= ADMINFLAG_KICKME;
04568       break;
04569    case 118: /* v: Lower all users listen volume */
04570       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_voldown_cb, NULL);
04571       break;
04572    case 86: /* V: Raise all users listen volume */
04573       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_volup_cb, NULL);
04574       break;
04575    case 115: /* s: Lower all users speaking volume */
04576       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_voldown_cb, NULL);
04577       break;
04578    case 83: /* S: Raise all users speaking volume */
04579       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_volup_cb, NULL);
04580       break;
04581    case 82: /* R: Reset all volume levels */
04582       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_reset_vol_cb, NULL);
04583       break;
04584    case 114: /* r: Reset user's volume level */
04585       reset_volumes(user);
04586       break;
04587    case 85: /* U: Raise user's listen volume */
04588       tweak_listen_volume(user, VOL_UP);
04589       break;
04590    case 117: /* u: Lower user's listen volume */
04591       tweak_listen_volume(user, VOL_DOWN);
04592       break;
04593    case 84: /* T: Raise user's talk volume */
04594       tweak_talk_volume(user, VOL_UP);
04595       break;
04596    case 116: /* t: Lower user's talk volume */
04597       tweak_talk_volume(user, VOL_DOWN);
04598       break;
04599    case 'E': /* E: Extend conference */
04600       if (rt_extend_conf(args.confno)) {
04601          res = -1;
04602       }
04603       break;
04604    }
04605 
04606    if (args.user) {
04607       /* decrement reference from find_user */
04608       ao2_ref(user, -1);
04609    }
04610 usernotfound:
04611    AST_LIST_UNLOCK(&confs);
04612 
04613    dispose_conf(cnf);
04614    pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
04615 
04616    return 0;
04617 }

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

Definition at line 2064 of file app_meetme.c.

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

Referenced by conf_run().

02065 {
02066    struct announce_listitem *current;
02067    struct ast_conference *conf = data;
02068    int res;
02069    char filename[PATH_MAX] = "";
02070    AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
02071    AST_LIST_HEAD_INIT_NOLOCK(&local_list);
02072 
02073    while (!conf->announcethread_stop) {
02074       ast_mutex_lock(&conf->announcelistlock);
02075       if (conf->announcethread_stop) {
02076          ast_mutex_unlock(&conf->announcelistlock);
02077          break;
02078       }
02079       if (AST_LIST_EMPTY(&conf->announcelist))
02080          ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
02081 
02082       AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
02083       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
02084 
02085       ast_mutex_unlock(&conf->announcelistlock);
02086       if (conf->announcethread_stop) {
02087          break;
02088       }
02089 
02090       for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
02091          ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
02092          if (!ast_fileexists(current->namerecloc, NULL, NULL))
02093             continue;
02094          if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
02095             if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
02096                res = ast_waitstream(current->confchan, "");
02097             if (!res) {
02098                ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
02099                if (!ast_streamfile(current->confchan, filename, current->language))
02100                   ast_waitstream(current->confchan, "");
02101             }
02102          }
02103          if (current->announcetype == CONF_HASLEFT) {
02104             ast_filedelete(current->namerecloc, NULL);
02105          }
02106       }
02107    }
02108 
02109    /* thread marked to stop, clean up */
02110    while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
02111       ast_filedelete(current->namerecloc, NULL);
02112       ao2_ref(current, -1);
02113    }
02114    return NULL;
02115 }

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

Definition at line 5131 of file app_meetme.c.

References ast_answer(), ast_indicate(), and sla_trunk_ref::chan.

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

05132 {
05133    ast_answer(chan);
05134    ast_indicate(chan, -1);
05135 }

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]

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

References ao2_container_alloc, ao2_ref, ast_atomic_fetchadd_int(), ast_calloc, ast_copy_string(), AST_FORMAT_SLINEAR, ast_free, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy, ast_mutex_init, AST_PTHREADT_NULL, ast_request(), ast_set_read_format(), ast_set_write_format(), ast_test_status_update, ast_verb, conf_map, ast_conference::confno, LOG_WARNING, ast_channel::uniqueid, and user_no_cmp().

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

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

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

Definition at line 2117 of file app_meetme.c.

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

Referenced by conf_run().

02118 {
02119    if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02120       return 1;
02121    }
02122 
02123    return (chan->_state == AST_STATE_UP);
02124 }

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

Definition at line 984 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

00985 {
00986    int res;
00987    int x;
00988 
00989    while (len) {
00990       if (block) {
00991          x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
00992          res = ioctl(fd, DAHDI_IOMUX, &x);
00993       } else
00994          res = 0;
00995       if (res >= 0)
00996          res = write(fd, data, len);
00997       if (res < 1) {
00998          if (errno != EAGAIN) {
00999             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
01000             return -1;
01001          } else
01002             return 0;
01003       }
01004       len -= res;
01005       data += res;
01006    }
01007 
01008    return 0;
01009 }

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

The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command).

Definition at line 4621 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, 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, user_chan_cb(), and ast_conference::usercontainer.

Referenced by load_module().

04621                                                                           {
04622    char *params;
04623    struct ast_conference *conf = NULL;
04624    struct ast_conf_user *user = NULL;
04625    AST_DECLARE_APP_ARGS(args,
04626       AST_APP_ARG(channel);
04627       AST_APP_ARG(command);
04628    );
04629 
04630    if (ast_strlen_zero(data)) {
04631       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
04632       return -1;
04633    }
04634    
04635    params = ast_strdupa(data);
04636    AST_STANDARD_APP_ARGS(args, params);
04637 
04638    if (!args.channel) {
04639       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
04640       return -1;
04641    }
04642 
04643    if (!args.command) {
04644       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
04645       return -1;
04646    }
04647 
04648    AST_LIST_LOCK(&confs);
04649    AST_LIST_TRAVERSE(&confs, conf, list) {
04650       if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
04651          break;
04652       }
04653    }
04654    
04655    if (!user) {
04656       ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
04657       AST_LIST_UNLOCK(&confs);
04658       return 0;
04659    }
04660    
04661    /* perform the specified action */
04662    switch (*args.command) {
04663       case 77: /* M: Mute */ 
04664          user->adminflags |= ADMINFLAG_MUTED;
04665          break;
04666       case 109: /* m: Unmute */ 
04667          user->adminflags &= ~ADMINFLAG_MUTED;
04668          break;
04669       case 107: /* k: Kick user */ 
04670          user->adminflags |= ADMINFLAG_KICKME;
04671          break;
04672       default: /* unknown command */
04673          ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
04674          break;
04675    }
04676    ao2_ref(user, -1);
04677    AST_LIST_UNLOCK(&confs);
04678    
04679    return 0;
04680 }

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

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

01285 {
01286    static const char * const cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
01287 
01288    int len = strlen(word);
01289    int which = 0;
01290    struct ast_conference *cnf = NULL;
01291    struct ast_conf_user *usr = NULL;
01292    char *confno = NULL;
01293    char usrno[50] = "";
01294    char *myline, *ret = NULL;
01295    
01296    if (pos == 1) {      /* Command */
01297       return ast_cli_complete(word, cmds, state);
01298    } else if (pos == 2) {  /* Conference Number */
01299       AST_LIST_LOCK(&confs);
01300       AST_LIST_TRAVERSE(&confs, cnf, list) {
01301          if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
01302             ret = cnf->confno;
01303             break;
01304          }
01305       }
01306       ret = ast_strdup(ret); /* dup before releasing the lock */
01307       AST_LIST_UNLOCK(&confs);
01308       return ret;
01309    } else if (pos == 3) {
01310       /* User Number || Conf Command option*/
01311       if (strstr(line, "mute") || strstr(line, "kick")) {
01312          if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
01313             return ast_strdup("all");
01314          which++;
01315          AST_LIST_LOCK(&confs);
01316 
01317          /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
01318          myline = ast_strdupa(line);
01319          if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
01320             while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
01321                ;
01322          }
01323          
01324          AST_LIST_TRAVERSE(&confs, cnf, list) {
01325             if (!strcmp(confno, cnf->confno))
01326                 break;
01327          }
01328 
01329          if (cnf) {
01330             struct ao2_iterator user_iter;
01331             user_iter = ao2_iterator_init(cnf->usercontainer, 0);
01332 
01333             while((usr = ao2_iterator_next(&user_iter))) {
01334                snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
01335                if (!strncasecmp(word, usrno, len) && ++which > state) {
01336                   ao2_ref(usr, -1);
01337                   break;
01338                }
01339                ao2_ref(usr, -1);
01340             }
01341             ao2_iterator_destroy(&user_iter);
01342             AST_LIST_UNLOCK(&confs);
01343             return usr ? ast_strdup(usrno) : NULL;
01344          }
01345       }
01346    }
01347 
01348    return NULL;
01349 }

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

The meetme() application.

Definition at line 4109 of file app_meetme.c.

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

04110 {
04111    int res = -1;
04112    char confno[MAX_CONFNUM] = "";
04113    int allowretry = 0;
04114    int retrycnt = 0;
04115    struct ast_conference *cnf = NULL;
04116    struct ast_flags64 confflags = {0};
04117    struct ast_flags config_flags = { 0 };
04118    int dynamic = 0;
04119    int empty = 0, empty_no_pin = 0;
04120    int always_prompt = 0;
04121    const char *notdata;
04122    char *info, the_pin[MAX_PIN] = "";
04123    AST_DECLARE_APP_ARGS(args,
04124       AST_APP_ARG(confno);
04125       AST_APP_ARG(options);
04126       AST_APP_ARG(pin);
04127    );
04128    char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
04129 
04130    if (ast_strlen_zero(data)) {
04131       allowretry = 1;
04132       notdata = "";
04133    } else {
04134       notdata = data;
04135    }
04136    
04137    if (chan->_state != AST_STATE_UP)
04138       ast_answer(chan);
04139 
04140    info = ast_strdupa(notdata);
04141 
04142    AST_STANDARD_APP_ARGS(args, info);  
04143 
04144    if (args.confno) {
04145       ast_copy_string(confno, args.confno, sizeof(confno));
04146       if (ast_strlen_zero(confno)) {
04147          allowretry = 1;
04148       }
04149    }
04150    
04151    if (args.pin)
04152       ast_copy_string(the_pin, args.pin, sizeof(the_pin));
04153 
04154    if (args.options) {
04155       ast_app_parse_options64(meetme_opts, &confflags, optargs, args.options);
04156       dynamic = ast_test_flag64(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
04157       if (ast_test_flag64(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
04158          strcpy(the_pin, "q");
04159 
04160       empty = ast_test_flag64(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
04161       empty_no_pin = ast_test_flag64(&confflags, CONFFLAG_EMPTYNOPIN);
04162       always_prompt = ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
04163    }
04164 
04165    do {
04166       if (retrycnt > 3)
04167          allowretry = 0;
04168       if (empty) {
04169          int i;
04170          struct ast_config *cfg;
04171          struct ast_variable *var;
04172          int confno_int;
04173 
04174          /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
04175          if ((empty_no_pin) || (!dynamic)) {
04176             cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
04177             if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
04178                var = ast_variable_browse(cfg, "rooms");
04179                while (var) {
04180                   char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
04181                   if (!strcasecmp(var->name, "conf")) {
04182                      int found = 0;
04183                      ast_copy_string(parse, var->value, sizeof(parse));
04184                      confno_tmp = strsep(&stringp, "|,");
04185                      if (!dynamic) {
04186                         /* For static:  run through the list and see if this conference is empty */
04187                         AST_LIST_LOCK(&confs);
04188                         AST_LIST_TRAVERSE(&confs, cnf, list) {
04189                            if (!strcmp(confno_tmp, cnf->confno)) {
04190                               /* The conference exists, therefore it's not empty */
04191                               found = 1;
04192                               break;
04193                            }
04194                         }
04195                         AST_LIST_UNLOCK(&confs);
04196                         if (!found) {
04197                            /* At this point, we have a confno_tmp (static conference) that is empty */
04198                            if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
04199                               /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
04200                                * Case 2:  empty_no_pin and pin is blank (but not NULL)
04201                                * Case 3:  not empty_no_pin
04202                                */
04203                               ast_copy_string(confno, confno_tmp, sizeof(confno));
04204                               break;
04205                            }
04206                         }
04207                      }
04208                   }
04209                   var = var->next;
04210                }
04211                ast_config_destroy(cfg);
04212             }
04213 
04214             if (ast_strlen_zero(confno) && (cfg = ast_load_realtime_multientry("meetme", "confno LIKE", "%", SENTINEL))) {
04215                const char *catg;
04216                for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
04217                   const char *confno_tmp = ast_variable_retrieve(cfg, catg, "confno");
04218                   const char *pin_tmp = ast_variable_retrieve(cfg, catg, "pin");
04219                   if (ast_strlen_zero(confno_tmp)) {
04220                      continue;
04221                   }
04222                   if (!dynamic) {
04223                      int found = 0;
04224                      /* For static:  run through the list and see if this conference is empty */
04225                      AST_LIST_LOCK(&confs);
04226                      AST_LIST_TRAVERSE(&confs, cnf, list) {
04227                         if (!strcmp(confno_tmp, cnf->confno)) {
04228                            /* The conference exists, therefore it's not empty */
04229                            found = 1;
04230                            break;
04231                         }
04232                      }
04233                      AST_LIST_UNLOCK(&confs);
04234                      if (!found) {
04235                         /* At this point, we have a confno_tmp (realtime conference) that is empty */
04236                         if ((empty_no_pin && ast_strlen_zero(pin_tmp)) || (!empty_no_pin)) {
04237                            /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
04238                             * Case 2:  empty_no_pin and pin is blank (but not NULL)
04239                             * Case 3:  not empty_no_pin
04240                             */
04241                            ast_copy_string(confno, confno_tmp, sizeof(confno));
04242                            break;
04243                         }
04244                      }
04245                   }
04246                }
04247                ast_config_destroy(cfg);
04248             }
04249          }
04250 
04251          /* Select first conference number not in use */
04252          if (ast_strlen_zero(confno) && dynamic) {
04253             AST_LIST_LOCK(&confs);
04254             for (i = 0; i < ARRAY_LEN(conf_map); i++) {
04255                if (!conf_map[i]) {
04256                   snprintf(confno, sizeof(confno), "%d", i);
04257                   conf_map[i] = 1;
04258                   break;
04259                }
04260             }
04261             AST_LIST_UNLOCK(&confs);
04262          }
04263 
04264          /* Not found? */
04265          if (ast_strlen_zero(confno)) {
04266             res = ast_streamfile(chan, "conf-noempty", chan->language);
04267             if (!res)
04268                ast_waitstream(chan, "");
04269          } else {
04270             if (sscanf(confno, "%30d", &confno_int) == 1) {
04271                if (!ast_test_flag64(&confflags, CONFFLAG_QUIET)) {
04272                   res = ast_streamfile(chan, "conf-enteringno", chan->language);
04273                   if (!res) {
04274                      ast_waitstream(chan, "");
04275                      res = ast_say_digits(chan, confno_int, "", chan->language);
04276                   }
04277                }
04278             } else {
04279                ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
04280             }
04281          }
04282       }
04283 
04284       while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
04285          /* Prompt user for conference number */
04286          res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
04287          if (res < 0) {
04288             /* Don't try to validate when we catch an error */
04289             confno[0] = '\0';
04290             allowretry = 0;
04291             break;
04292          }
04293       }
04294       if (!ast_strlen_zero(confno)) {
04295          /* Check the validity of the conference */
04296          cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
04297             sizeof(the_pin), 1, &confflags);
04298          if (!cnf) {
04299             int too_early = 0;
04300 
04301             cnf = find_conf_realtime(chan, confno, 1, dynamic, 
04302                the_pin, sizeof(the_pin), 1, &confflags, &too_early, optargs);
04303             if (rt_schedule && too_early)
04304                allowretry = 0;
04305          }
04306 
04307          if (!cnf) {
04308             if (allowretry) {
04309                confno[0] = '\0';
04310                res = ast_streamfile(chan, "conf-invalid", chan->language);
04311                if (!res)
04312                   ast_waitstream(chan, "");
04313                res = -1;
04314             }
04315          } else {
04316             if (((!ast_strlen_zero(cnf->pin)       &&
04317                !ast_test_flag64(&confflags, CONFFLAG_ADMIN)) ||
04318                  (!ast_strlen_zero(cnf->pinadmin)  &&
04319                    ast_test_flag64(&confflags, CONFFLAG_ADMIN)) ||
04320                     (!ast_strlen_zero(cnf->pin) &&
04321                       ast_strlen_zero(cnf->pinadmin) &&
04322                       ast_test_flag64(&confflags, CONFFLAG_ADMIN))) &&
04323                 (!(cnf->users == 0 && cnf->isdynamic))) {
04324                char pin[MAX_PIN] = "";
04325                int j;
04326 
04327                /* Allow the pin to be retried up to 3 times */
04328                for (j = 0; j < 3; j++) {
04329                   if (*the_pin && (always_prompt == 0)) {
04330                      ast_copy_string(pin, the_pin, sizeof(pin));
04331                      res = 0;
04332                   } else {
04333                      /* Prompt user for pin if pin is required */
04334                      res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
04335                   }
04336                   if (res >= 0) {
04337                      if ((!strcasecmp(pin, cnf->pin) &&
04338                           (ast_strlen_zero(cnf->pinadmin) ||
04339                            !ast_test_flag64(&confflags, CONFFLAG_ADMIN))) ||
04340                           (!ast_strlen_zero(cnf->pinadmin) &&
04341                            !strcasecmp(pin, cnf->pinadmin))) {
04342                         /* Pin correct */
04343                         allowretry = 0;
04344                         if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
04345                            if (!ast_strlen_zero(cnf->adminopts)) {
04346                               char *opts = ast_strdupa(cnf->adminopts);
04347                               ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
04348                            }
04349                         } else {
04350                            if (!ast_strlen_zero(cnf->useropts)) {
04351                               char *opts = ast_strdupa(cnf->useropts);
04352                               ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
04353                            }
04354                         }
04355                         /* Run the conference */
04356                         ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
04357                         res = conf_run(chan, cnf, &confflags, optargs);
04358                         break;
04359                      } else {
04360                         /* Pin invalid */
04361                         if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
04362                            res = ast_waitstream(chan, AST_DIGIT_ANY);
04363                            ast_stopstream(chan);
04364                         } else {
04365                            ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
04366                            break;
04367                         }
04368                         if (res < 0)
04369                            break;
04370                         pin[0] = res;
04371                         pin[1] = '\0';
04372                         res = -1;
04373                         if (allowretry)
04374                            confno[0] = '\0';
04375                      }
04376                   } else {
04377                      /* failed when getting the pin */
04378                      res = -1;
04379                      allowretry = 0;
04380                      /* see if we need to get rid of the conference */
04381                      break;
04382                   }
04383 
04384                   /* Don't retry pin with a static pin */
04385                   if (*the_pin && (always_prompt == 0)) {
04386                      break;
04387                   }
04388                }
04389             } else {
04390                /* No pin required */
04391                allowretry = 0;
04392 
04393                /* For RealTime conferences without a pin 
04394                 * should still support loading options
04395                 */
04396                if (!ast_strlen_zero(cnf->useropts)) {
04397                   char *opts = ast_strdupa(cnf->useropts);
04398                   ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
04399                }
04400 
04401                /* Run the conference */
04402                res = conf_run(chan, cnf, &confflags, optargs);
04403             }
04404             dispose_conf(cnf);
04405             cnf = NULL;
04406          }
04407       }
04408    } while (allowretry);
04409 
04410    if (cnf)
04411       dispose_conf(cnf);
04412    
04413    return res;
04414 }

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

Definition at line 1763 of file app_meetme.c.

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

Referenced by conf_run().

01764 {
01765    int x;
01766 
01767    /* read any frames that may be waiting on the channel
01768       and throw them away
01769    */
01770    if (chan) {
01771       struct ast_frame *f;
01772 
01773       /* when no frames are available, this will wait
01774          for 1 millisecond maximum
01775       */
01776       while (ast_waitfor(chan, 1)) {
01777          f = ast_read(chan);
01778          if (f)
01779             ast_frfree(f);
01780          else /* channel was hung up or something else happened */
01781             break;
01782       }
01783    }
01784 
01785    /* flush any data sitting in the pseudo channel */
01786    x = DAHDI_FLUSH_ALL;
01787    if (ioctl(fd, DAHDI_FLUSH, &x))
01788       ast_log(LOG_WARNING, "Error flushing channel\n");
01789 
01790 }

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

References ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethread_stop, ao2_ref, ast_cond_signal, ast_filedelete(), AST_FRAME_BITS, ast_frfree, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_translator_free_path(), ast_conference::chan, ast_conference::confno, announce_listitem::entry, EVENT_FLAG_CALL, manager_event, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, announce_listitem::namerecloc, ast_conference::transframe, and ast_conference::transpath.

Referenced by dispose_conf().

01796 {
01797    int x;
01798    struct announce_listitem *item;
01799    
01800    AST_LIST_REMOVE(&confs, conf, list);
01801    manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01802 
01803    if (conf->recording == MEETME_RECORD_ACTIVE) {
01804       conf->recording = MEETME_RECORD_TERMINATE;
01805       AST_LIST_UNLOCK(&confs);
01806       while (1) {
01807          usleep(1);
01808          AST_LIST_LOCK(&confs);
01809          if (conf->recording == MEETME_RECORD_OFF)
01810             break;
01811          AST_LIST_UNLOCK(&confs);
01812       }
01813    }
01814 
01815    for (x = 0; x < AST_FRAME_BITS; x++) {
01816       if (conf->transframe[x])
01817          ast_frfree(conf->transframe[x]);
01818       if (conf->transpath[x])
01819          ast_translator_free_path(conf->transpath[x]);
01820    }
01821    if (conf->announcethread != AST_PTHREADT_NULL) {
01822       ast_mutex_lock(&conf->announcelistlock);
01823       conf->announcethread_stop = 1;
01824       ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01825       ast_cond_signal(&conf->announcelist_addition);
01826       ast_mutex_unlock(&conf->announcelistlock);
01827       pthread_join(conf->announcethread, NULL);
01828    
01829       while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01830          ast_filedelete(item->namerecloc, NULL);
01831          ao2_ref(item, -1);
01832       }
01833       ast_mutex_destroy(&conf->announcelistlock);
01834    }
01835 
01836    if (conf->origframe)
01837       ast_frfree(conf->origframe);
01838    if (conf->lchan)
01839       ast_hangup(conf->lchan);
01840    if (conf->chan)
01841       ast_hangup(conf->chan);
01842    if (conf->fd >= 0)
01843       close(conf->fd);
01844    if (conf->recordingfilename) {
01845       ast_free(conf->recordingfilename);
01846    }
01847    if (conf->usercontainer) {
01848       ao2_ref(conf->usercontainer, -1);
01849    }
01850    if (conf->recordingformat) {
01851       ast_free(conf->recordingformat);
01852    }
01853    ast_mutex_destroy(&conf->playlock);
01854    ast_mutex_destroy(&conf->listenlock);
01855    ast_mutex_destroy(&conf->recordthreadlock);
01856    ast_mutex_destroy(&conf->announcethreadlock);
01857    ast_free(conf);
01858 
01859    return 0;
01860 }

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

Definition at line 1102 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, and len().

Referenced by conf_run().

01103 {
01104    unsigned char *data;
01105    int len;
01106    int res = -1;
01107 
01108    if (!ast_check_hangup(chan))
01109       res = ast_autoservice_start(chan);
01110 
01111    AST_LIST_LOCK(&confs);
01112 
01113    switch(sound) {
01114    case ENTER:
01115       data = enter;
01116       len = sizeof(enter);
01117       break;
01118    case LEAVE:
01119       data = leave;
01120       len = sizeof(leave);
01121       break;
01122    default:
01123       data = NULL;
01124       len = 0;
01125    }
01126    if (data) {
01127       careful_write(conf->fd, data, len, 1);
01128    }
01129 
01130    AST_LIST_UNLOCK(&confs);
01131 
01132    if (!res) 
01133       ast_autoservice_stop(chan);
01134 }

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

Definition at line 1862 of file app_meetme.c.

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

Referenced by conf_run().

01864 {
01865    struct ast_conf_user *user;
01866    struct ao2_iterator user_iter;
01867 
01868    user_iter = ao2_iterator_init(conf->usercontainer, 0);
01869    while ((user = ao2_iterator_next(&user_iter))) {
01870       if (user == sender) {
01871          ao2_ref(user, -1);
01872          continue;
01873       }
01874       if (ast_write(user->chan, f) < 0)
01875          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01876       ao2_ref(user, -1);
01877    }
01878    ao2_iterator_destroy(&user_iter);
01879 }

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

Definition at line 2188 of file app_meetme.c.

References 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, ao2_alloc, ao2_callback, ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_lock, ao2_ref, ao2_unlock, ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_cond_signal, ast_config_AST_SPOOL_DIR, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DEVICE_INUSE, ast_devstate_changed(), AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_silence(), ast_exists_extension(), ast_fileexists(), AST_FORMAT_SLINEAR, ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_free, ast_frfree, AST_FRIENDLY_OFFSET, ast_func_write(), ast_goto_if_exists(), ast_hangup(), ast_indicate(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_NEXT, 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(), ast_set_write_format(), 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, can_write(), careful_write(), ast_conf_user::chan, ast_conference::chan, conf_flush(), CONF_HASJOIN, conf_play(), conf_queue_dtmf(), CONF_SIZE, conf_start_moh(), CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_DURATION_LIMIT, CONFFLAG_DURATION_STOP, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROMSG, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_KEYEXIT, CONFFLAG_KICK_CONTINUE, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_SLA_STATION, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, ast_conference::dahdiconf, DATE_FORMAT, dtmfstr, ast_conference::endalert, ast_conference::endtime, ENTER, announce_listitem::entry, errno, EVENT_FLAG_CALL, exitcontext, f, ast_channel::fds, ast_frame::frametype, ast_conference::gmuted, ast_channel::language, ast_conference::lchan, ast_conference::listenlock, ast_conference::locked, LOG_WARNING, ast_conference::markedusers, ast_conference::maxusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, MEETME_RECORD_ACTIVE, ast_channel::monitor, ast_channel::name, ast_conf_user::namerecloc, OBJ_NODATA, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_EXITKEYS, OPT_ARG_INTROMSG, OPT_ARG_MOH_CLASS, OPT_ARG_WAITMARKED, ast_conference::origframe, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_conference::playlock, ast_channel::rawwriteformat, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, rt_extend_conf(), S_COR, set_talk_volume(), set_user_talking(), SLA_EVENT_HOLD, sla_queue_event_conf(), strsep(), ast_channel::tech, THRESHOLD_SILENCE, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_conference::uniqueid, ast_channel::uniqueid, user, user_max_cmp(), user_set_kickme_cb(), user_set_muted_cb(), user_set_unmuted_cb(), ast_conference::usercontainer, ast_conf_user::userflags, ast_conference::users, var, and VOL_UP.

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

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

Definition at line 2034 of file app_meetme.c.

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

Referenced by conf_run().

02035 {
02036    char *original_moh;
02037 
02038    ast_channel_lock(chan);
02039    original_moh = ast_strdupa(chan->musicclass);
02040    ast_string_field_set(chan, musicclass, musicclass);
02041    ast_channel_unlock(chan);
02042 
02043    ast_moh_start(chan, original_moh, NULL);
02044 
02045    ast_channel_lock(chan);
02046    ast_string_field_set(chan, musicclass, original_moh);
02047    ast_channel_unlock(chan);
02048 }

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

The MeetmeCount application.

Definition at line 4063 of file app_meetme.c.

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

Referenced by load_module().

04064 {
04065    int res = 0;
04066    struct ast_conference *conf;
04067    int count;
04068    char *localdata;
04069    char val[80] = "0"; 
04070    AST_DECLARE_APP_ARGS(args,
04071       AST_APP_ARG(confno);
04072       AST_APP_ARG(varname);
04073    );
04074 
04075    if (ast_strlen_zero(data)) {
04076       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
04077       return -1;
04078    }
04079    
04080    if (!(localdata = ast_strdupa(data)))
04081       return -1;
04082 
04083    AST_STANDARD_APP_ARGS(args, localdata);
04084    
04085    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
04086 
04087    if (conf) {
04088       count = conf->users;
04089       dispose_conf(conf);
04090       conf = NULL;
04091    } else
04092       count = 0;
04093 
04094    if (!ast_strlen_zero(args.varname)) {
04095       /* have var so load it and exit */
04096       snprintf(val, sizeof(val), "%d", count);
04097       pbx_builtin_setvar_helper(chan, args.varname, val);
04098    } else {
04099       if (chan->_state != AST_STATE_UP) {
04100          ast_answer(chan);
04101       }
04102       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
04103    }
04104 
04105    return res;
04106 }

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

Definition at line 6238 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

06239 {
06240    struct sla_trunk_ref *trunk_ref;
06241 
06242    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
06243       return NULL;
06244 
06245    trunk_ref->trunk = trunk;
06246 
06247    return trunk_ref;
06248 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 6448 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, sla_trunk_ref::entry, exten, sla_trunk::name, sla_station::name, PRIORITY_HINT, sla_registrar, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_destroy().

06449 {
06450    struct sla_trunk_ref *trunk_ref;
06451 
06452    if (!ast_strlen_zero(station->autocontext)) {
06453       AST_RWLIST_RDLOCK(&sla_trunks);
06454       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06455          char exten[AST_MAX_EXTENSION];
06456          char hint[AST_MAX_APP];
06457          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06458          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06459          ast_context_remove_extension(station->autocontext, exten, 
06460             1, sla_registrar);
06461          ast_context_remove_extension(station->autocontext, hint, 
06462             PRIORITY_HINT, sla_registrar);
06463       }
06464       AST_RWLIST_UNLOCK(&sla_trunks);
06465    }
06466 
06467    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
06468       ast_free(trunk_ref);
06469 
06470    ast_string_field_free_memory(station);
06471    ast_free(station);
06472 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 6434 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_station_ref::entry, sla_registrar, and sla_trunk::stations.

Referenced by sla_destroy().

06435 {
06436    struct sla_station_ref *station_ref;
06437 
06438    if (!ast_strlen_zero(trunk->autocontext))
06439       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
06440 
06441    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
06442       ast_free(station_ref);
06443 
06444    ast_string_field_free_memory(trunk);
06445    ast_free(trunk);
06446 }

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

Definition at line 5951 of file app_meetme.c.

References 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_strdupa, ast_channel::caller, sla_trunk::chan, sla_trunk_ref::chan, sla_trunk::device, MAX_CONFNUM, sla, strsep(), and sla_trunk_ref::trunk.

Referenced by sla_station_exec().

05952 {
05953    struct dial_trunk_args *args = data;
05954    struct ast_dial *dial;
05955    char *tech, *tech_data;
05956    enum ast_dial_result dial_res;
05957    char conf_name[MAX_CONFNUM];
05958    struct ast_conference *conf;
05959    struct ast_flags64 conf_flags = { 0 };
05960    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
05961    int caller_is_saved;
05962    struct ast_party_caller caller;
05963 
05964    if (!(dial = ast_dial_create())) {
05965       ast_mutex_lock(args->cond_lock);
05966       ast_cond_signal(args->cond);
05967       ast_mutex_unlock(args->cond_lock);
05968       return NULL;
05969    }
05970 
05971    tech_data = ast_strdupa(trunk_ref->trunk->device);
05972    tech = strsep(&tech_data, "/");
05973    if (ast_dial_append(dial, tech, tech_data) == -1) {
05974       ast_mutex_lock(args->cond_lock);
05975       ast_cond_signal(args->cond);
05976       ast_mutex_unlock(args->cond_lock);
05977       ast_dial_destroy(dial);
05978       return NULL;
05979    }
05980 
05981    /* Do we need to save of the caller ID data? */
05982    caller_is_saved = 0;
05983    if (!sla.attempt_callerid) {
05984       caller_is_saved = 1;
05985       caller = trunk_ref->chan->caller;
05986       ast_party_caller_init(&trunk_ref->chan->caller);
05987    }
05988 
05989    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
05990 
05991    /* Restore saved caller ID */
05992    if (caller_is_saved) {
05993       ast_party_caller_free(&trunk_ref->chan->caller);
05994       trunk_ref->chan->caller = caller;
05995    }
05996 
05997    if (dial_res != AST_DIAL_RESULT_TRYING) {
05998       ast_mutex_lock(args->cond_lock);
05999       ast_cond_signal(args->cond);
06000       ast_mutex_unlock(args->cond_lock);
06001       ast_dial_destroy(dial);
06002       return NULL;
06003    }
06004 
06005    for (;;) {
06006       unsigned int done = 0;
06007       switch ((dial_res = ast_dial_state(dial))) {
06008       case AST_DIAL_RESULT_ANSWERED:
06009          trunk_ref->trunk->chan = ast_dial_answered(dial);
06010       case AST_DIAL_RESULT_HANGUP:
06011       case AST_DIAL_RESULT_INVALID:
06012       case AST_DIAL_RESULT_FAILED:
06013       case AST_DIAL_RESULT_TIMEOUT:
06014       case AST_DIAL_RESULT_UNANSWERED:
06015          done = 1;
06016       case AST_DIAL_RESULT_TRYING:
06017       case AST_DIAL_RESULT_RINGING:
06018       case AST_DIAL_RESULT_PROGRESS:
06019       case AST_DIAL_RESULT_PROCEEDING:
06020          break;
06021       }
06022       if (done)
06023          break;
06024    }
06025 
06026    if (!trunk_ref->trunk->chan) {
06027       ast_mutex_lock(args->cond_lock);
06028       ast_cond_signal(args->cond);
06029       ast_mutex_unlock(args->cond_lock);
06030       ast_dial_join(dial);
06031       ast_dial_destroy(dial);
06032       return NULL;
06033    }
06034 
06035    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
06036    ast_set_flag64(&conf_flags, 
06037       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
06038       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
06039    conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan, NULL);
06040 
06041    ast_mutex_lock(args->cond_lock);
06042    ast_cond_signal(args->cond);
06043    ast_mutex_unlock(args->cond_lock);
06044 
06045    if (conf) {
06046       conf_run(trunk_ref->trunk->chan, conf, &conf_flags, NULL);
06047       dispose_conf(conf);
06048       conf = NULL;
06049    }
06050 
06051    /* If the trunk is going away, it is definitely now IDLE. */
06052    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06053 
06054    trunk_ref->trunk->chan = NULL;
06055    trunk_ref->trunk->on_hold = 0;
06056 
06057    ast_dial_join(dial);
06058    ast_dial_destroy(dial);
06059 
06060    return NULL;
06061 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Decrement reference counts, as incremented by find_conf().

Definition at line 1953 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(), run_station(), sla_station_exec(), and sla_trunk_exec().

01954 {
01955    int res = 0;
01956    int confno_int = 0;
01957 
01958    AST_LIST_LOCK(&confs);
01959    if (ast_atomic_dec_and_test(&conf->refcount)) {
01960       /* Take the conference room number out of an inuse state */
01961       if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
01962          conf_map[confno_int] = 0;
01963       }
01964       conf_free(conf);
01965       res = 1;
01966    }
01967    AST_LIST_UNLOCK(&confs);
01968 
01969    return res;
01970 }

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]

Definition at line 3959 of file app_meetme.c.

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

Referenced by conf_exec(), and count_exec().

03961 {
03962    struct ast_config *cfg;
03963    struct ast_variable *var;
03964    struct ast_flags config_flags = { 0 };
03965    struct ast_conference *cnf;
03966 
03967    AST_DECLARE_APP_ARGS(args,
03968       AST_APP_ARG(confno);
03969       AST_APP_ARG(pin);
03970       AST_APP_ARG(pinadmin);
03971    );
03972 
03973    /* Check first in the conference list */
03974    ast_debug(1, "The requested confno is '%s'?\n", confno);
03975    AST_LIST_LOCK(&confs);
03976    AST_LIST_TRAVERSE(&confs, cnf, list) {
03977       ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
03978       if (!strcmp(confno, cnf->confno)) 
03979          break;
03980    }
03981    if (cnf) {
03982       cnf->refcount += refcount;
03983    }
03984    AST_LIST_UNLOCK(&confs);
03985 
03986    if (!cnf) {
03987       if (dynamic) {
03988          /* No need to parse meetme.conf */
03989          ast_debug(1, "Building dynamic conference '%s'\n", confno);
03990          if (dynamic_pin) {
03991             if (dynamic_pin[0] == 'q') {
03992                /* Query the user to enter a PIN */
03993                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
03994                   return NULL;
03995             }
03996             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan, NULL);
03997          } else {
03998             cnf = build_conf(confno, "", "", make, dynamic, refcount, chan, NULL);
03999          }
04000       } else {
04001          /* Check the config */
04002          cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
04003          if (!cfg) {
04004             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
04005             return NULL;
04006          } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04007             ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
04008             return NULL;
04009          }
04010 
04011          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
04012             char parse[MAX_SETTINGS];
04013 
04014             if (strcasecmp(var->name, "conf"))
04015                continue;
04016 
04017             ast_copy_string(parse, var->value, sizeof(parse));
04018 
04019             AST_STANDARD_APP_ARGS(args, parse);
04020             ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
04021             if (!strcasecmp(args.confno, confno)) {
04022                /* Bingo it's a valid conference */
04023                cnf = build_conf(args.confno,
04024                      S_OR(args.pin, ""),
04025                      S_OR(args.pinadmin, ""),
04026                      make, dynamic, refcount, chan, NULL);
04027                break;
04028             }
04029          }
04030          if (!var) {
04031             ast_debug(1, "%s isn't a valid conference\n", confno);
04032          }
04033          ast_config_destroy(cfg);
04034       }
04035    } else if (dynamic_pin) {
04036       /* Correct for the user selecting 'D' instead of 'd' to have
04037          someone join into a conference that has already been created
04038          with a pin. */
04039       if (dynamic_pin[0] == 'q') {
04040          dynamic_pin[0] = '\0';
04041       }
04042    }
04043 
04044    if (cnf) {
04045       if (confflags && !cnf->chan &&
04046           !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
04047           ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
04048          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
04049          ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
04050       }
04051       
04052       if (confflags && !cnf->chan &&
04053           ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
04054          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
04055          ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
04056       }
04057    }
04058 
04059    return cnf;
04060 }

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]

Definition at line 3775 of file app_meetme.c.

References ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), AST_MAX_EXTENSION, ast_strdupa, ast_streamfile(), ast_strftime(), ast_tvnow(), ast_variables_destroy(), ast_waitstream(), ast_conference::confno, DATE_FORMAT, ast_channel::language, ast_conference::list, OPTIONS_LEN, ast_conference::refcount, and var.

Referenced by conf_exec().

03777 {
03778    struct ast_variable *var, *origvar;
03779    struct ast_conference *cnf;
03780 
03781    *too_early = 0;
03782 
03783    /* Check first in the conference list */
03784    AST_LIST_LOCK(&confs);
03785    AST_LIST_TRAVERSE(&confs, cnf, list) {
03786       if (!strcmp(confno, cnf->confno)) {
03787          break;
03788       }
03789    }
03790    if (cnf) {
03791       cnf->refcount += refcount;
03792    }
03793    AST_LIST_UNLOCK(&confs);
03794 
03795    if (!cnf) {
03796       char *pin = NULL, *pinadmin = NULL; /* For temp use */
03797       int maxusers = 0;
03798       struct timeval now;
03799       char recordingfilename[256] = "";
03800       char recordingformat[11] = "";
03801       char currenttime[32] = "";
03802       char eatime[32] = "";
03803       char bookid[51] = "";
03804       char recordingtmp[AST_MAX_EXTENSION] = "";
03805       char useropts[OPTIONS_LEN + 1] = ""; /* Used for RealTime conferences */
03806       char adminopts[OPTIONS_LEN + 1] = "";
03807       struct ast_tm tm, etm;
03808       struct timeval endtime = { .tv_sec = 0 };
03809       const char *var2;
03810 
03811       if (rt_schedule) {
03812          now = ast_tvnow();
03813 
03814          ast_localtime(&now, &tm, NULL);
03815          ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03816 
03817          ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
03818 
03819          var = ast_load_realtime("meetme", "confno",
03820             confno, "starttime <= ", currenttime, "endtime >= ",
03821             currenttime, NULL);
03822 
03823          if (!var && fuzzystart) {
03824             now = ast_tvnow();
03825             now.tv_sec += fuzzystart;
03826 
03827             ast_localtime(&now, &tm, NULL);
03828             ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03829             var = ast_load_realtime("meetme", "confno",
03830                confno, "starttime <= ", currenttime, "endtime >= ",
03831                currenttime, NULL);
03832          }
03833 
03834          if (!var && earlyalert) {
03835             now = ast_tvnow();
03836             now.tv_sec += earlyalert;
03837             ast_localtime(&now, &etm, NULL);
03838             ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
03839             var = ast_load_realtime("meetme", "confno",
03840                confno, "starttime <= ", eatime, "endtime >= ",
03841                currenttime, NULL);
03842             if (var) {
03843                *too_early = 1;
03844             }
03845          }
03846 
03847       } else {
03848           var = ast_load_realtime("meetme", "confno", confno, NULL);
03849       }
03850 
03851       if (!var) {
03852          return NULL;
03853       }
03854 
03855       if (rt_schedule && *too_early) {
03856          /* Announce that the caller is early and exit */
03857          if (!ast_streamfile(chan, "conf-has-not-started", chan->language)) {
03858             ast_waitstream(chan, "");
03859          }
03860          ast_variables_destroy(var);
03861          return NULL;
03862       }
03863 
03864       for (origvar = var; var; var = var->next) {
03865          if (!strcasecmp(var->name, "pin")) {
03866             pin = ast_strdupa(var->value);
03867          } else if (!strcasecmp(var->name, "adminpin")) {
03868             pinadmin = ast_strdupa(var->value);
03869          } else if (!strcasecmp(var->name, "bookId")) {
03870             ast_copy_string(bookid, var->value, sizeof(bookid));
03871          } else if (!strcasecmp(var->name, "opts")) {
03872             ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
03873          } else if (!strcasecmp(var->name, "maxusers")) {
03874             maxusers = atoi(var->value);
03875          } else if (!strcasecmp(var->name, "adminopts")) {
03876             ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
03877          } else if (!strcasecmp(var->name, "recordingfilename")) {
03878             ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
03879          } else if (!strcasecmp(var->name, "recordingformat")) {
03880             ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
03881          } else if (!strcasecmp(var->name, "endtime")) {
03882             struct ast_tm endtime_tm;
03883             ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
03884             endtime = ast_mktime(&endtime_tm, NULL);
03885          }
03886       }
03887 
03888       ast_variables_destroy(origvar);
03889 
03890       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan, NULL);
03891 
03892       if (cnf) {
03893          struct ast_flags64 tmp_flags;
03894 
03895          cnf->maxusers = maxusers;
03896          cnf->endalert = endalert;
03897          cnf->endtime = endtime.tv_sec;
03898          cnf->useropts = ast_strdup(useropts);
03899          cnf->adminopts = ast_strdup(adminopts);
03900          cnf->bookid = ast_strdup(bookid);
03901          cnf->recordingfilename = ast_strdup(recordingfilename);
03902          cnf->recordingformat = ast_strdup(recordingformat);
03903 
03904          /* Parse the other options into confflags -- need to do this in two
03905           * steps, because the parse_options routine zeroes the buffer. */
03906          ast_app_parse_options64(meetme_opts, &tmp_flags, optargs, useropts);
03907          ast_copy_flags64(confflags, &tmp_flags, tmp_flags.flags);
03908 
03909          if (strchr(cnf->useropts, 'r')) {
03910             if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */
03911                ast_channel_lock(chan);
03912                if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
03913                   ast_free(cnf->recordingfilename);
03914                   cnf->recordingfilename = ast_strdup(var2);
03915                }
03916                ast_channel_unlock(chan);
03917                if (ast_strlen_zero(cnf->recordingfilename)) {
03918                   snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, chan->uniqueid);
03919                   ast_free(cnf->recordingfilename);
03920                   cnf->recordingfilename = ast_strdup(recordingtmp);
03921                }
03922             }
03923             if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */
03924                ast_channel_lock(chan);
03925                if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
03926                   ast_free(cnf->recordingformat);
03927                   cnf->recordingformat = ast_strdup(var2);
03928                }
03929                ast_channel_unlock(chan);
03930                if (ast_strlen_zero(cnf->recordingformat)) {
03931                   ast_free(cnf->recordingformat);
03932                   cnf->recordingformat = ast_strdup("wav");
03933                }
03934             }
03935             ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
03936          }
03937       }
03938    }
03939 
03940    if (cnf) {
03941       if (confflags->flags && !cnf->chan &&
03942           !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
03943           ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03944          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03945          ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03946       }
03947 
03948       if (confflags && !cnf->chan &&
03949           ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
03950          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03951          ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
03952       }
03953    }
03954 
03955    return cnf;
03956 }

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

Definition at line 4416 of file app_meetme.c.

References ao2_find, user, and ast_conference::usercontainer.

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

04417 {
04418    struct ast_conf_user *user = NULL;
04419    int cid;
04420    
04421    sscanf(callerident, "%30i", &cid);
04422    if (conf && callerident) {
04423       user = ao2_find(conf->usercontainer, &cid, 0);
04424       /* reference decremented later in admin_exec */
04425       return user;
04426    }
04427    return NULL;
04428 }

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

Definition at line 2050 of file app_meetme.c.

References CONF_HASJOIN.

Referenced by announce_thread().

02051 {
02052    switch (type) {
02053    case CONF_HASLEFT:
02054       return "conf-hasleft";
02055       break;
02056    case CONF_HASJOIN:
02057       return "conf-hasjoin";
02058       break;
02059    default:
02060       return "";
02061    }
02062 }

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

Definition at line 974 of file app_meetme.c.

00975 {
00976    if (x > 0)
00977       return "(talking)";
00978    else if (x < 0)
00979       return "(unmonitored)";
00980    else 
00981       return "(not talking)";
00982 }

static int load_config ( int  reload  )  [static]

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

06885 {
06886    load_config_meetme();
06887 
06888    if (reload && sla.thread != AST_PTHREADT_NULL) {
06889       sla_queue_event(SLA_EVENT_RELOAD);
06890       ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
06891          "and will be completed when the system is idle.\n");
06892       return 0;
06893    }
06894    
06895    return sla_load_config(0);
06896 }

static void load_config_meetme ( void   )  [static]

Definition at line 4910 of file app_meetme.c.

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

Referenced by load_config().

04911 {
04912    struct ast_config *cfg;
04913    struct ast_flags config_flags = { 0 };
04914    const char *val;
04915 
04916    if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
04917       return;
04918    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04919       ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
04920       return;
04921    }
04922 
04923    audio_buffers = DEFAULT_AUDIO_BUFFERS;
04924 
04925    /*  Scheduling support is off by default */
04926    rt_schedule = 0;
04927    fuzzystart = 0;
04928    earlyalert = 0;
04929    endalert = 0;
04930    extendby = 0;
04931 
04932    /*  Logging of participants defaults to ON for compatibility reasons */
04933    rt_log_members = 1;  
04934 
04935    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
04936       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
04937          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
04938          audio_buffers = DEFAULT_AUDIO_BUFFERS;
04939       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
04940          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
04941             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
04942          audio_buffers = DEFAULT_AUDIO_BUFFERS;
04943       }
04944       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
04945          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
04946    }
04947 
04948    if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
04949       rt_schedule = ast_true(val);
04950    if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
04951       rt_log_members = ast_true(val);
04952    if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
04953       if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
04954          ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
04955          fuzzystart = 0;
04956       } 
04957    }
04958    if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
04959       if ((sscanf(val, "%30d", &earlyalert) != 1)) {
04960          ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
04961          earlyalert = 0;
04962       } 
04963    }
04964    if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
04965       if ((sscanf(val, "%30d", &endalert) != 1)) {
04966          ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
04967          endalert = 0;
04968       } 
04969    }
04970    if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
04971       if ((sscanf(val, "%30d", &extendby) != 1)) {
04972          ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
04973          extendby = 0;
04974       } 
04975    }
04976 
04977    ast_config_destroy(cfg);
04978 }

static int load_module ( void   )  [static]

Definition at line 7109 of file app_meetme.c.

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

07110 {
07111    int res = 0;
07112 
07113    res |= load_config(0);
07114 
07115    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07116    res |= ast_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute);
07117    res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute);
07118    res |= ast_manager_register_xml("MeetmeList", EVENT_FLAG_REPORTING, action_meetmelist);
07119    res |= ast_register_application_xml(app4, channel_admin_exec);
07120    res |= ast_register_application_xml(app3, admin_exec);
07121    res |= ast_register_application_xml(app2, count_exec);
07122    res |= ast_register_application_xml(app, conf_exec);
07123    res |= ast_register_application_xml(slastation_app, sla_station_exec);
07124    res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
07125 
07126 #ifdef TEST_FRAMEWORK
07127    AST_TEST_REGISTER(test_meetme_data_provider);
07128 #endif
07129    ast_data_register_multiple(meetme_data_providers, ARRAY_LEN(meetme_data_providers));
07130 
07131    res |= ast_devstate_prov_add("Meetme", meetmestate);
07132    res |= ast_devstate_prov_add("SLA", sla_state);
07133 
07134    res |= ast_custom_function_register(&meetme_info_acf);
07135    ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
07136 
07137    return res;
07138 }

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

Definition at line 1509 of file app_meetme.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_free, ast_str_create(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, 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.

01510 {
01511    /* Process the command */
01512    struct ast_str *cmdline = NULL;
01513    int i = 0;
01514 
01515    switch (cmd) {
01516    case CLI_INIT:
01517       e->command = "meetme {lock|unlock|mute|unmute|kick}";
01518       e->usage =
01519          "Usage: meetme (un)lock|(un)mute|kick <confno> <usernumber>\n"
01520          "       Executes a command for the conference or on a conferee\n";
01521       return NULL;
01522    case CLI_GENERATE:
01523       return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01524    }
01525 
01526    if (a->argc > 8)
01527       ast_cli(a->fd, "Invalid Arguments.\n");
01528    /* Check for length so no buffer will overflow... */
01529    for (i = 0; i < a->argc; i++) {
01530       if (strlen(a->argv[i]) > 100)
01531          ast_cli(a->fd, "Invalid Arguments.\n");
01532    }
01533 
01534    /* Max confno length */
01535    if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01536       return CLI_FAILURE;
01537    }
01538 
01539    if (a->argc < 1) {
01540       ast_free(cmdline);
01541       return CLI_SHOWUSAGE;
01542    }
01543 
01544    ast_str_set(&cmdline, 0, "%s", a->argv[2]);  /* Argv 2: conference number */
01545    if (strstr(a->argv[1], "lock")) {
01546       if (strcmp(a->argv[1], "lock") == 0) {
01547          /* Lock */
01548          ast_str_append(&cmdline, 0, ",L");
01549       } else {
01550          /* Unlock */
01551          ast_str_append(&cmdline, 0, ",l");
01552       }
01553    } else if (strstr(a->argv[1], "mute")) { 
01554       if (a->argc < 4) {
01555          ast_free(cmdline);
01556          return CLI_SHOWUSAGE;
01557       }
01558       if (strcmp(a->argv[1], "mute") == 0) {
01559          /* Mute */
01560          if (strcmp(a->argv[3], "all") == 0) {
01561             ast_str_append(&cmdline, 0, ",N");
01562          } else {
01563             ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);  
01564          }
01565       } else {
01566          /* Unmute */
01567          if (strcmp(a->argv[3], "all") == 0) {
01568             ast_str_append(&cmdline, 0, ",n");
01569          } else {
01570             ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
01571          }
01572       }
01573    } else if (strcmp(a->argv[1], "kick") == 0) {
01574       if (a->argc < 4) {
01575          ast_free(cmdline);
01576          return CLI_SHOWUSAGE;
01577       }
01578       if (strcmp(a->argv[3], "all") == 0) {
01579          /* Kick all */
01580          ast_str_append(&cmdline, 0, ",K");
01581       } else {
01582          /* Kick a single user */
01583          ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
01584       }
01585    } else {
01586       ast_free(cmdline);
01587       return CLI_SHOWUSAGE;
01588    }
01589 
01590    ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
01591 
01592    admin_exec(NULL, ast_str_buffer(cmdline));
01593    ast_free(cmdline);
01594 
01595    return CLI_SUCCESS;
01596 }

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

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

06975 {
06976    struct ast_conference *cnf;
06977    struct ast_data *data_meetme, *data_meetme_users;
06978 
06979    AST_LIST_LOCK(&confs);
06980    AST_LIST_TRAVERSE(&confs, cnf, list) {
06981       data_meetme = ast_data_add_node(data_root, "meetme");
06982       if (!data_meetme) {
06983          continue;
06984       }
06985 
06986       ast_data_add_structure(ast_conference, data_meetme, cnf);
06987 
06988       if (ao2_container_count(cnf->usercontainer)) {
06989          data_meetme_users = ast_data_add_node(data_meetme, "users");
06990          if (!data_meetme_users) {
06991             ast_data_remove_node(data_root, data_meetme);
06992             continue;
06993          }
06994 
06995          ao2_callback(cnf->usercontainer, OBJ_NODATA, user_add_provider_cb, data_meetme_users); 
06996       }
06997 
06998       if (!ast_data_search_match(search, data_meetme)) {
06999          ast_data_remove_node(data_root, data_meetme);
07000       }
07001    }
07002    AST_LIST_UNLOCK(&confs);
07003 
07004    return 0;
07005 }

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

Definition at line 1351 of file app_meetme.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_free, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_str_buffer(), ast_str_create(), ast_str_set(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd(), ast_conference::confno, ast_cli_args::fd, ast_conference::isdynamic, ast_cli_args::line, ast_conference::locked, ast_conference::markedusers, MAX_CONFNUM, MC_DATA_FORMAT, MC_HEADER_FORMAT, ast_cli_args::n, ast_cli_args::pos, ast_conference::start, total, ast_cli_entry::usage, ast_conference::users, and ast_cli_args::word.

01352 {
01353    /* Process the command */
01354    struct ast_conf_user *user;
01355    struct ast_conference *cnf;
01356    int hr, min, sec;
01357    int i = 0, total = 0;
01358    time_t now;
01359    struct ast_str *cmdline = NULL;
01360 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s  %-8s  %-6s\n"
01361 #define MC_DATA_FORMAT "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s  %-6s\n"
01362 
01363    switch (cmd) {
01364    case CLI_INIT:
01365       e->command = "meetme list [concise]";
01366       e->usage =
01367          "Usage: meetme list [concise] <confno> \n"
01368          "       List all or a specific conference.\n";
01369       return NULL;
01370    case CLI_GENERATE:
01371       return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01372    }
01373 
01374    /* Check for length so no buffer will overflow... */
01375    for (i = 0; i < a->argc; i++) {
01376       if (strlen(a->argv[i]) > 100)
01377          ast_cli(a->fd, "Invalid Arguments.\n");
01378    }
01379 
01380    /* Max confno length */
01381    if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01382       return CLI_FAILURE;
01383    }
01384 
01385    if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], "concise"))) {
01386       /* List all the conferences */   
01387       int concise = (a->argc == 3 && !strcasecmp(a->argv[2], "concise"));
01388       now = time(NULL);
01389       AST_LIST_LOCK(&confs);
01390       if (AST_LIST_EMPTY(&confs)) {
01391          if (!concise) {
01392             ast_cli(a->fd, "No active MeetMe conferences.\n");
01393          }
01394          AST_LIST_UNLOCK(&confs);
01395          ast_free(cmdline);
01396          return CLI_SUCCESS;
01397       }
01398       if (!concise) {
01399          ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
01400       }
01401       AST_LIST_TRAVERSE(&confs, cnf, list) {
01402          if (cnf->markedusers == 0) {
01403             ast_str_set(&cmdline, 0, "N/A ");
01404          } else {
01405             ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
01406          }
01407          hr = (now - cnf->start) / 3600;
01408          min = ((now - cnf->start) % 3600) / 60;
01409          sec = (now - cnf->start) % 60;
01410          if (!concise) {
01411             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");
01412          } else {
01413             ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
01414                cnf->confno,
01415                cnf->users,
01416                cnf->markedusers,
01417                hr, min, sec,
01418                cnf->isdynamic,
01419                cnf->locked);
01420          }
01421 
01422          total += cnf->users;
01423       }
01424       AST_LIST_UNLOCK(&confs);
01425       if (!concise) {
01426          ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
01427       }
01428       ast_free(cmdline);
01429       return CLI_SUCCESS;
01430    } else if (strcmp(a->argv[1], "list") == 0) {
01431       struct ao2_iterator user_iter;
01432       int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
01433       /* List all the users in a conference */
01434       if (AST_LIST_EMPTY(&confs)) {
01435          if (!concise) {
01436             ast_cli(a->fd, "No active MeetMe conferences.\n");
01437          }
01438          ast_free(cmdline);
01439          return CLI_SUCCESS;  
01440       }
01441       /* Find the right conference */
01442       AST_LIST_LOCK(&confs);
01443       AST_LIST_TRAVERSE(&confs, cnf, list) {
01444          if (strcmp(cnf->confno, a->argv[2]) == 0) {
01445             break;
01446          }
01447       }
01448       if (!cnf) {
01449          if (!concise)
01450             ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
01451          AST_LIST_UNLOCK(&confs);
01452          ast_free(cmdline);
01453          return CLI_SUCCESS;
01454       }
01455       /* Show all the users */
01456       time(&now);
01457       user_iter = ao2_iterator_init(cnf->usercontainer, 0);
01458       while((user = ao2_iterator_next(&user_iter))) {
01459          hr = (now - user->jointime) / 3600;
01460          min = ((now - user->jointime) % 3600) / 60;
01461          sec = (now - user->jointime) % 60;
01462          if (!concise) {
01463             ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
01464                user->user_no,
01465                S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
01466                S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
01467                user->chan->name,
01468                ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "(Admin)" : "",
01469                ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "(Listen only)" : "",
01470                user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
01471                user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
01472                istalking(user->talking), hr, min, sec); 
01473          } else {
01474             ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
01475                user->user_no,
01476                S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, ""),
01477                S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, ""),
01478                user->chan->name,
01479                ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "1" : "",
01480                ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "1" : "",
01481                user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
01482                user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
01483                user->talking, hr, min, sec);
01484          }
01485          ao2_ref(user, -1);
01486       }
01487       ao2_iterator_destroy(&user_iter);
01488       if (!concise) {
01489          ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
01490       }
01491       AST_LIST_UNLOCK(&confs);
01492       ast_free(cmdline);
01493       return CLI_SUCCESS;
01494    }
01495    if (a->argc < 2) {
01496       ast_free(cmdline);
01497       return CLI_SHOWUSAGE;
01498    }
01499 
01500    ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
01501 
01502    admin_exec(NULL, ast_str_buffer(cmdline));
01503    ast_free(cmdline);
01504 
01505    return CLI_SUCCESS;
01506 }

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

Definition at line 4682 of file app_meetme.c.

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

Referenced by action_meetmemute(), and action_meetmeunmute().

04683 {
04684    struct ast_conference *conf;
04685    struct ast_conf_user *user;
04686    const char *confid = astman_get_header(m, "Meetme");
04687    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
04688    int userno;
04689 
04690    if (ast_strlen_zero(confid)) {
04691       astman_send_error(s, m, "Meetme conference not specified");
04692       return 0;
04693    }
04694 
04695    if (ast_strlen_zero(userid)) {
04696       astman_send_error(s, m, "Meetme user number not specified");
04697       return 0;
04698    }
04699 
04700    userno = strtoul(userid, &userid, 10);
04701 
04702    if (*userid) {
04703       astman_send_error(s, m, "Invalid user number");
04704       return 0;
04705    }
04706 
04707    /* Look in the conference list */
04708    AST_LIST_LOCK(&confs);
04709    AST_LIST_TRAVERSE(&confs, conf, list) {
04710       if (!strcmp(confid, conf->confno))
04711          break;
04712    }
04713 
04714    if (!conf) {
04715       AST_LIST_UNLOCK(&confs);
04716       astman_send_error(s, m, "Meetme conference does not exist");
04717       return 0;
04718    }
04719 
04720    user = ao2_find(conf->usercontainer, &userno, 0);
04721 
04722    if (!user) {
04723       AST_LIST_UNLOCK(&confs);
04724       astman_send_error(s, m, "User number not found");
04725       return 0;
04726    }
04727 
04728    if (mute)
04729       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
04730    else
04731       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
04732 
04733    AST_LIST_UNLOCK(&confs);
04734 
04735    ast_log(LOG_NOTICE, "Requested to %smute conf %s user %d userchan %s uniqueid %s\n", mute ? "" : "un", conf->confno, user->user_no, user->chan->name, user->chan->uniqueid);
04736 
04737    ao2_ref(user, -1);
04738    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
04739    return 0;
04740 }

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

Callback for devicestate providers.

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

04889 {
04890    struct ast_conference *conf;
04891 
04892    /* Find conference */
04893    AST_LIST_LOCK(&confs);
04894    AST_LIST_TRAVERSE(&confs, conf, list) {
04895       if (!strcmp(data, conf->confno))
04896          break;
04897    }
04898    AST_LIST_UNLOCK(&confs);
04899    if (!conf)
04900       return AST_DEVICE_INVALID;
04901 
04902 
04903    /* SKREP to fill */
04904    if (!conf->users)
04905       return AST_DEVICE_NOT_INUSE;
04906 
04907    return AST_DEVICE_INUSE;
04908 }

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

Definition at line 6250 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::entry, 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().

06251 {
06252    struct sla_ringing_trunk *ringing_trunk;
06253 
06254    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
06255       return NULL;
06256    
06257    ringing_trunk->trunk = trunk;
06258    ringing_trunk->ring_begin = ast_tvnow();
06259 
06260    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
06261 
06262    ast_mutex_lock(&sla.lock);
06263    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
06264    ast_mutex_unlock(&sla.lock);
06265 
06266    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06267 
06268    return ringing_trunk;
06269 }

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

Definition at line 4823 of file app_meetme.c.

References 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_conference::lchan, ast_conference::listenlock, MEETME_RECORD_ACTIVE, ast_conference::origframe, ast_conference::recordingfilename, ast_conference::recordingformat, and ast_conference::transframe.

04824 {
04825    struct ast_conference *cnf = args;
04826    struct ast_frame *f = NULL;
04827    int flags;
04828    struct ast_filestream *s = NULL;
04829    int res = 0;
04830    int x;
04831    const char *oldrecordingfilename = NULL;
04832 
04833    if (!cnf || !cnf->lchan) {
04834       pthread_exit(0);
04835    }
04836 
04837    ast_stopstream(cnf->lchan);
04838    flags = O_CREAT | O_TRUNC | O_WRONLY;
04839 
04840 
04841    cnf->recording = MEETME_RECORD_ACTIVE;
04842    while (ast_waitfor(cnf->lchan, -1) > -1) {
04843       if (cnf->recording == MEETME_RECORD_TERMINATE) {
04844          AST_LIST_LOCK(&confs);
04845          AST_LIST_UNLOCK(&confs);
04846          break;
04847       }
04848       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
04849          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
04850          oldrecordingfilename = cnf->recordingfilename;
04851       }
04852       
04853       f = ast_read(cnf->lchan);
04854       if (!f) {
04855          res = -1;
04856          break;
04857       }
04858       if (f->frametype == AST_FRAME_VOICE) {
04859          ast_mutex_lock(&cnf->listenlock);
04860          for (x = 0; x < AST_FRAME_BITS; x++) {
04861             /* Free any translations that have occured */
04862             if (cnf->transframe[x]) {
04863                ast_frfree(cnf->transframe[x]);
04864                cnf->transframe[x] = NULL;
04865             }
04866          }
04867          if (cnf->origframe)
04868             ast_frfree(cnf->origframe);
04869          cnf->origframe = ast_frdup(f);
04870          ast_mutex_unlock(&cnf->listenlock);
04871          if (s)
04872             res = ast_writestream(s, f);
04873          if (res) {
04874             ast_frfree(f);
04875             break;
04876          }
04877       }
04878       ast_frfree(f);
04879    }
04880    cnf->recording = MEETME_RECORD_OFF;
04881    if (s)
04882       ast_closestream(s);
04883    
04884    pthread_exit(0);
04885 }

static int reload ( void   )  [static]

Definition at line 7140 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

07141 {
07142    ast_unload_realtime("meetme");
07143    return load_config(1);
07144 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 1094 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_RXGAIN, AST_OPTION_TXGAIN, and user.

Referenced by admin_exec(), and user_reset_vol_cb().

01095 {
01096    signed char zero_volume = 0;
01097 
01098    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
01099    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
01100 }

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

Definition at line 1972 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, and var.

Referenced by admin_exec(), and conf_run().

01973 {
01974    char currenttime[32];
01975    char endtime[32];
01976    struct timeval now;
01977    struct ast_tm tm;
01978    struct ast_variable *var, *orig_var;
01979    char bookid[51];
01980 
01981    if (!extendby) {
01982       return 0;
01983    }
01984 
01985    now = ast_tvnow();
01986 
01987    ast_localtime(&now, &tm, NULL);
01988    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
01989 
01990    var = ast_load_realtime("meetme", "confno",
01991       confno, "startTime<= ", currenttime,
01992       "endtime>= ", currenttime, NULL);
01993 
01994    orig_var = var;
01995 
01996    /* Identify the specific RealTime conference */
01997    while (var) {
01998       if (!strcasecmp(var->name, "bookid")) {
01999          ast_copy_string(bookid, var->value, sizeof(bookid));
02000       }
02001       if (!strcasecmp(var->name, "endtime")) {
02002          ast_copy_string(endtime, var->value, sizeof(endtime));
02003       }
02004 
02005       var = var->next;
02006    }
02007    ast_variables_destroy(orig_var);
02008 
02009    ast_strptime(endtime, DATE_FORMAT, &tm);
02010    now = ast_mktime(&tm, NULL);
02011 
02012    now.tv_sec += extendby;
02013 
02014    ast_localtime(&now, &tm, NULL);
02015    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02016    strcat(currenttime, "0"); /* Seconds needs to be 00 */
02017 
02018    var = ast_load_realtime("meetme", "confno",
02019       confno, "startTime<= ", currenttime,
02020       "endtime>= ", currenttime, NULL);
02021 
02022    /* If there is no conflict with extending the conference, update the DB */
02023    if (!var) {
02024       ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
02025       ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
02026       return 0;
02027 
02028    }
02029 
02030    ast_variables_destroy(var);
02031    return -1;
02032 }

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

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

05138 {
05139    struct sla_station *station;
05140    struct sla_trunk_ref *trunk_ref;
05141    struct ast_str *conf_name = ast_str_create(16);
05142    struct ast_flags64 conf_flags = { 0 };
05143    struct ast_conference *conf;
05144 
05145    {
05146       struct run_station_args *args = data;
05147       station = args->station;
05148       trunk_ref = args->trunk_ref;
05149       ast_mutex_lock(args->cond_lock);
05150       ast_cond_signal(args->cond);
05151       ast_mutex_unlock(args->cond_lock);
05152       /* args is no longer valid here. */
05153    }
05154 
05155    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
05156    ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
05157    ast_set_flag64(&conf_flags, 
05158       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05159    answer_trunk_chan(trunk_ref->chan);
05160    conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan, NULL);
05161    if (conf) {
05162       conf_run(trunk_ref->chan, conf, &conf_flags, NULL);
05163       dispose_conf(conf);
05164       conf = NULL;
05165    }
05166    trunk_ref->chan = NULL;
05167    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05168       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05169       ast_str_append(&conf_name, 0, ",K");
05170       admin_exec(NULL, ast_str_buffer(conf_name));
05171       trunk_ref->trunk->hold_stations = 0;
05172       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05173    }
05174 
05175    ast_dial_join(station->dial);
05176    ast_dial_destroy(station->dial);
05177    station->dial = NULL;
05178    ast_free(conf_name);
05179 
05180    return NULL;
05181 }

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

Definition at line 2126 of file app_meetme.c.

References ast_manager_event, ast_conference::chan, ast_conference::confno, EVENT_FLAG_CALL, ast_channel::name, ast_channel::uniqueid, and user.

Referenced by set_user_talking().

02127 {
02128    ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking",
02129          "Channel: %s\r\n"
02130          "Uniqueid: %s\r\n"
02131          "Meetme: %s\r\n"
02132          "Usernum: %d\r\n"
02133          "Status: %s\r\n",
02134          chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
02135 }

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

Definition at line 1023 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_TXGAIN, and user.

Referenced by tweak_listen_volume().

01024 {
01025    char gain_adjust;
01026 
01027    /* attempt to make the adjustment in the channel driver;
01028       if successful, don't adjust in the frame reading routine
01029    */
01030    gain_adjust = gain_map[volume + 5];
01031 
01032    return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
01033 }

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

Definition at line 1011 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_RXGAIN, and user.

Referenced by conf_run(), and tweak_talk_volume().

01012 {
01013    char gain_adjust;
01014 
01015    /* attempt to make the adjustment in the channel driver;
01016       if successful, don't adjust in the frame reading routine
01017    */
01018    gain_adjust = gain_map[volume + 5];
01019 
01020    return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
01021 }

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

References ast_conference::chan, send_talking_event(), and user.

Referenced by conf_run().

02138 {
02139    int last_talking = user->talking;
02140    if (last_talking == talking)
02141       return;
02142 
02143    user->talking = talking;
02144 
02145    if (monitor) {
02146       /* Check if talking state changed. Take care of -1 which means unmonitored */
02147       int was_talking = (last_talking > 0);
02148       int now_talking = (talking > 0);
02149       if (was_talking != now_talking) {
02150          send_talking_event(chan, conf, user, now_talking);
02151       }
02152    }
02153 }

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

Definition at line 6592 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(), sla_station_ref::entry, 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_station_ref::station, sla_trunk::stations, strsep(), sla_station::trunks, value, and var.

Referenced by sla_build_station().

06593 {
06594    struct sla_trunk *trunk;
06595    struct sla_trunk_ref *trunk_ref;
06596    struct sla_station_ref *station_ref;
06597    char *trunk_name, *options, *cur;
06598 
06599    options = ast_strdupa(var->value);
06600    trunk_name = strsep(&options, ",");
06601    
06602    AST_RWLIST_RDLOCK(&sla_trunks);
06603    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
06604       if (!strcasecmp(trunk->name, trunk_name))
06605          break;
06606    }
06607 
06608    AST_RWLIST_UNLOCK(&sla_trunks);
06609    if (!trunk) {
06610       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
06611       return;
06612    }
06613    if (!(trunk_ref = create_trunk_ref(trunk)))
06614       return;
06615    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
06616 
06617    while ((cur = strsep(&options, ","))) {
06618       char *name, *value = cur;
06619       name = strsep(&value, "=");
06620       if (!strcasecmp(name, "ringtimeout")) {
06621          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
06622             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
06623                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06624             trunk_ref->ring_timeout = 0;
06625          }
06626       } else if (!strcasecmp(name, "ringdelay")) {
06627          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
06628             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
06629                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06630             trunk_ref->ring_delay = 0;
06631          }
06632       } else {
06633          ast_log(LOG_WARNING, "Invalid option '%s' for "
06634             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
06635       }
06636    }
06637 
06638    if (!(station_ref = sla_create_station_ref(station))) {
06639       ast_free(trunk_ref);
06640       return;
06641    }
06642    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
06643    AST_RWLIST_WRLOCK(&sla_trunks);
06644    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
06645    AST_RWLIST_UNLOCK(&sla_trunks);
06646    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
06647 }

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

Definition at line 6649 of file app_meetme.c.

References ast_calloc_with_stringfields, ast_log(), ast_string_field_set, ast_variable_browse(), ast_variable_retrieve(), LOG_WARNING, sla_station::name, sla_station::ring_timeout, sla_add_trunk_to_station(), and var.

Referenced by sla_load_config().

06650 {
06651    struct sla_station *station;
06652    struct ast_variable *var;
06653    const char *dev;
06654 
06655    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06656       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
06657       return -1;
06658    }
06659 
06660    if (!(station = ast_calloc_with_stringfields(1, struct sla_station, 32))) {
06661       return -1;
06662    }
06663 
06664    ast_string_field_set(station, name, cat);
06665    ast_string_field_set(station, device, dev);
06666 
06667    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06668       if (!strcasecmp(var->name, "trunk"))
06669          sla_add_trunk_to_station(station, var);
06670       else if (!strcasecmp(var->name, "autocontext"))
06671          ast_string_field_set(station, autocontext, var->value);
06672       else if (!strcasecmp(var->name, "ringtimeout")) {
06673          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
06674             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
06675                var->value, station->name);
06676             station->ring_timeout = 0;
06677          }
06678       } else if (!strcasecmp(var->name, "ringdelay")) {
06679          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
06680             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
06681                var->value, station->name);
06682             station->ring_delay = 0;
06683          }
06684       } else if (!strcasecmp(var->name, "hold")) {
06685          if (!strcasecmp(var->value, "private"))
06686             station->hold_access = SLA_HOLD_PRIVATE;
06687          else if (!strcasecmp(var->value, "open"))
06688             station->hold_access = SLA_HOLD_OPEN;
06689          else {
06690             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
06691                var->value, station->name);
06692          }
06693 
06694       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06695          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06696             var->name, var->lineno, SLA_CONFIG_FILE);
06697       }
06698    }
06699 
06700    if (!ast_strlen_zero(station->autocontext)) {
06701       struct ast_context *context;
06702       struct sla_trunk_ref *trunk_ref;
06703       context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
06704       if (!context) {
06705          ast_log(LOG_ERROR, "Failed to automatically find or create "
06706             "context '%s' for SLA!\n", station->autocontext);
06707          destroy_station(station);
06708          return -1;
06709       }
06710       /* The extension for when the handset goes off-hook.
06711        * exten => station1,1,SLAStation(station1) */
06712       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
06713          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
06714          ast_log(LOG_ERROR, "Failed to automatically create extension "
06715             "for trunk '%s'!\n", station->name);
06716          destroy_station(station);
06717          return -1;
06718       }
06719       AST_RWLIST_RDLOCK(&sla_trunks);
06720       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06721          char exten[AST_MAX_EXTENSION];
06722          char hint[AST_MAX_APP];
06723          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06724          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06725          /* Extension for this line button 
06726           * exten => station1_line1,1,SLAStation(station1_line1) */
06727          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
06728             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
06729             ast_log(LOG_ERROR, "Failed to automatically create extension "
06730                "for trunk '%s'!\n", station->name);
06731             destroy_station(station);
06732             return -1;
06733          }
06734          /* Hint for this line button 
06735           * exten => station1_line1,hint,SLA:station1_line1 */
06736          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
06737             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
06738             ast_log(LOG_ERROR, "Failed to automatically create hint "
06739                "for trunk '%s'!\n", station->name);
06740             destroy_station(station);
06741             return -1;
06742          }
06743       }
06744       AST_RWLIST_UNLOCK(&sla_trunks);
06745    }
06746 
06747    AST_RWLIST_WRLOCK(&sla_stations);
06748    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
06749    AST_RWLIST_UNLOCK(&sla_stations);
06750 
06751    return 0;
06752 }

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

Definition at line 6517 of file app_meetme.c.

References ast_calloc_with_stringfields, ast_log(), ast_string_field_set, ast_variable_browse(), ast_variable_retrieve(), LOG_ERROR, LOG_WARNING, sla_trunk::name, sla_trunk::ring_timeout, sla_check_device(), and var.

Referenced by sla_load_config().

06518 {
06519    struct sla_trunk *trunk;
06520    struct ast_variable *var;
06521    const char *dev;
06522 
06523    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06524       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
06525       return -1;
06526    }
06527 
06528    if (sla_check_device(dev)) {
06529       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
06530          cat, dev);
06531       return -1;
06532    }
06533 
06534    if (!(trunk = ast_calloc_with_stringfields(1, struct sla_trunk, 32))) {
06535       return -1;
06536    }
06537 
06538    ast_string_field_set(trunk, name, cat);
06539    ast_string_field_set(trunk, device, dev);
06540 
06541    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06542       if (!strcasecmp(var->name, "autocontext"))
06543          ast_string_field_set(trunk, autocontext, var->value);
06544       else if (!strcasecmp(var->name, "ringtimeout")) {
06545          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
06546             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
06547                var->value, trunk->name);
06548             trunk->ring_timeout = 0;
06549          }
06550       } else if (!strcasecmp(var->name, "barge"))
06551          trunk->barge_disabled = ast_false(var->value);
06552       else if (!strcasecmp(var->name, "hold")) {
06553          if (!strcasecmp(var->value, "private"))
06554             trunk->hold_access = SLA_HOLD_PRIVATE;
06555          else if (!strcasecmp(var->value, "open"))
06556             trunk->hold_access = SLA_HOLD_OPEN;
06557          else {
06558             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
06559                var->value, trunk->name);
06560          }
06561       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06562          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06563             var->name, var->lineno, SLA_CONFIG_FILE);
06564       }
06565    }
06566 
06567    if (!ast_strlen_zero(trunk->autocontext)) {
06568       struct ast_context *context;
06569       context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
06570       if (!context) {
06571          ast_log(LOG_ERROR, "Failed to automatically find or create "
06572             "context '%s' for SLA!\n", trunk->autocontext);
06573          destroy_trunk(trunk);
06574          return -1;
06575       }
06576       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
06577          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
06578          ast_log(LOG_ERROR, "Failed to automatically create extension "
06579             "for trunk '%s'!\n", trunk->name);
06580          destroy_trunk(trunk);
06581          return -1;
06582       }
06583    }
06584 
06585    AST_RWLIST_WRLOCK(&sla_trunks);
06586    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
06587    AST_RWLIST_UNLOCK(&sla_trunks);
06588 
06589    return 0;
06590 }

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

References AST_LIST_TRAVERSE, sla_station::entry, sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), and sla_choose_ringing_trunk().

Referenced by sla_process_timers().

05750 {
05751    struct sla_station *station;
05752    int res = 0;
05753 
05754    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05755       struct sla_ringing_trunk *ringing_trunk;
05756       int time_left;
05757 
05758       /* Ignore stations already ringing */
05759       if (sla_check_ringing_station(station))
05760          continue;
05761 
05762       /* Ignore stations already on a call */
05763       if (sla_check_inuse_station(station))
05764          continue;
05765 
05766       /* Ignore stations that don't have one of their trunks ringing */
05767       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
05768          continue;
05769 
05770       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
05771          continue;
05772 
05773       /* If there is no time left, then the station needs to start ringing.
05774        * Return non-zero so that an event will be queued up an event to 
05775        * make that happen. */
05776       if (time_left <= 0) {
05777          res = 1;
05778          continue;
05779       }
05780 
05781       if (time_left < *timeout)
05782          *timeout = time_left;
05783    }
05784 
05785    return res;
05786 }

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 5666 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_station_ref::entry, sla_trunk_ref::entry, sla_ringing_station::entry, 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().

05667 {
05668    struct sla_ringing_trunk *ringing_trunk;
05669    struct sla_ringing_station *ringing_station;
05670    int res = 0;
05671 
05672    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05673       unsigned int ring_timeout = 0;
05674       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
05675       struct sla_trunk_ref *trunk_ref;
05676 
05677       /* If there are any ring timeouts specified for a specific trunk
05678        * on the station, then use the highest per-trunk ring timeout.
05679        * Otherwise, use the ring timeout set for the entire station. */
05680       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05681          struct sla_station_ref *station_ref;
05682          int trunk_time_elapsed, trunk_time_left;
05683 
05684          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05685             if (ringing_trunk->trunk == trunk_ref->trunk)
05686                break;
05687          }
05688          if (!ringing_trunk)
05689             continue;
05690 
05691          /* If there is a trunk that is ringing without a timeout, then the
05692           * only timeout that could matter is a global station ring timeout. */
05693          if (!trunk_ref->ring_timeout)
05694             break;
05695 
05696          /* This trunk on this station is ringing and has a timeout.
05697           * However, make sure this trunk isn't still ringing from a
05698           * previous timeout.  If so, don't consider it. */
05699          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
05700             if (station_ref->station == ringing_station->station)
05701                break;
05702          }
05703          if (station_ref)
05704             continue;
05705 
05706          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05707          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
05708          if (trunk_time_left > final_trunk_time_left)
05709             final_trunk_time_left = trunk_time_left;
05710       }
05711 
05712       /* No timeout was found for ringing trunks, and no timeout for the entire station */
05713       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
05714          continue;
05715 
05716       /* Compute how much time is left for a global station timeout */
05717       if (ringing_station->station->ring_timeout) {
05718          ring_timeout = ringing_station->station->ring_timeout;
05719          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
05720          time_left = (ring_timeout * 1000) - time_elapsed;
05721       }
05722 
05723       /* If the time left based on the per-trunk timeouts is smaller than the
05724        * global station ring timeout, use that. */
05725       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
05726          time_left = final_trunk_time_left;
05727 
05728       /* If there is no time left, the station needs to stop ringing */
05729       if (time_left <= 0) {
05730          AST_LIST_REMOVE_CURRENT(entry);
05731          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
05732          res = 1;
05733          continue;
05734       }
05735 
05736       /* There is still some time left for this station to ring, so save that
05737        * timeout if it is the first event scheduled to occur */
05738       if (time_left < *timeout)
05739          *timeout = time_left;
05740    }
05741    AST_LIST_TRAVERSE_SAFE_END;
05742 
05743    return res;
05744 }

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 5636 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, sla_ringing_trunk::entry, 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().

05637 {
05638    struct sla_ringing_trunk *ringing_trunk;
05639    int res = 0;
05640 
05641    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05642       int time_left, time_elapsed;
05643       if (!ringing_trunk->trunk->ring_timeout)
05644          continue;
05645       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05646       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
05647       if (time_left <= 0) {
05648          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
05649          AST_LIST_REMOVE_CURRENT(entry);
05650          sla_stop_ringing_trunk(ringing_trunk);
05651          res = 1;
05652          continue;
05653       }
05654       if (time_left < *timeout)
05655          *timeout = time_left;
05656    }
05657    AST_LIST_TRAVERSE_SAFE_END;
05658 
05659    return res;
05660 }

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

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

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

05107 {
05108    struct sla_station *station;
05109    struct sla_trunk_ref *trunk_ref;
05110 
05111    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05112       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05113          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
05114             || trunk_ref == exclude)
05115             continue;
05116          trunk_ref->state = state;
05117          ast_devstate_changed(sla_state_to_devstate(state), 
05118             "SLA:%s_%s", station->name, trunk->name);
05119          break;
05120       }
05121    }
05122 }

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

Definition at line 6504 of file app_meetme.c.

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

Referenced by sla_build_trunk().

06505 {
06506    char *tech, *tech_data;
06507 
06508    tech_data = ast_strdupa(device);
06509    tech = strsep(&tech_data, "/");
06510 
06511    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
06512       return -1;
06513 
06514    return 0;
06515 }

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 5385 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::entry, sla_failed_station::last_try, sla, and sla_failed_station::station.

Referenced by sla_ring_stations().

05386 {
05387    struct sla_failed_station *failed_station;
05388    int res = 0;
05389 
05390    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
05391       if (station != failed_station->station)
05392          continue;
05393       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
05394          AST_LIST_REMOVE_CURRENT(entry);
05395          ast_free(failed_station);
05396          break;
05397       }
05398       res = 1;
05399    }
05400    AST_LIST_TRAVERSE_SAFE_END
05401 
05402    return res;
05403 }

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

Check to see if a station is in use.

Definition at line 5470 of file app_meetme.c.

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

Referenced by sla_calc_station_delays(), and sla_ring_stations().

05471 {
05472    struct sla_trunk_ref *trunk_ref;
05473 
05474    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05475       if (trunk_ref->chan)
05476          return 1;
05477    }
05478 
05479    return 0;
05480 }

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

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

Referenced by sla_thread().

05829 {
05830    struct sla_station *station;
05831    struct sla_trunk *trunk;
05832 
05833    ast_mutex_lock(&sla.lock);
05834 
05835    if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
05836       || !AST_LIST_EMPTY(&sla.ringing_stations)) {
05837       ast_mutex_unlock(&sla.lock);
05838       return;
05839    }
05840 
05841    AST_RWLIST_RDLOCK(&sla_stations);
05842    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
05843       if (station->ref_count)
05844          break;
05845    }
05846    AST_RWLIST_UNLOCK(&sla_stations);
05847    if (station) {
05848       ast_mutex_unlock(&sla.lock);
05849       return;
05850    }
05851 
05852    AST_RWLIST_RDLOCK(&sla_trunks);
05853    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05854       if (trunk->ref_count)
05855          break;
05856    }
05857    AST_RWLIST_UNLOCK(&sla_trunks);
05858    if (trunk) {
05859       ast_mutex_unlock(&sla.lock);
05860       return;
05861    }
05862 
05863    /* We need to actually delete the previous versions of trunks and stations now */
05864    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_stations, station, entry) {
05865       AST_RWLIST_REMOVE_CURRENT(entry);
05866       ast_free(station);
05867    }
05868    AST_RWLIST_TRAVERSE_SAFE_END;
05869 
05870    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_trunks, trunk, entry) {
05871       AST_RWLIST_REMOVE_CURRENT(entry);
05872       ast_free(trunk);
05873    }
05874    AST_RWLIST_TRAVERSE_SAFE_END;
05875 
05876    /* yay */
05877    sla_load_config(1);
05878    sla.reload = 0;
05879 
05880    ast_mutex_unlock(&sla.lock);
05881 }

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

References AST_LIST_TRAVERSE, sla_ringing_station::entry, sla, and sla_ringing_station::station.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

05371 {
05372    struct sla_ringing_station *ringing_station;
05373 
05374    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
05375       if (station == ringing_station->station)
05376          return 1;
05377    }
05378 
05379    return 0;
05380 }

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

05502 {
05503    struct sla_trunk_ref *trunk_ref;
05504    unsigned int delay = UINT_MAX;
05505    int time_left, time_elapsed;
05506 
05507    if (!ringing_trunk)
05508       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
05509    else
05510       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
05511 
05512    if (!ringing_trunk || !trunk_ref)
05513       return delay;
05514 
05515    /* If this station has a ring delay specific to the highest priority
05516     * ringing trunk, use that.  Otherwise, use the ring delay specified
05517     * globally for the station. */
05518    delay = trunk_ref->ring_delay;
05519    if (!delay)
05520       delay = station->ring_delay;
05521    if (!delay)
05522       return INT_MAX;
05523 
05524    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05525    time_left = (delay * 1000) - time_elapsed;
05526 
05527    return time_left;
05528 }

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

Definition at line 5010 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla_trunk_ref::entry, 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().

05012 {
05013    struct sla_station_ref *station_ref;
05014    struct sla_trunk_ref *trunk_ref;
05015 
05016    /* For each station that has this call on hold, check for private hold. */
05017    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
05018       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
05019          if (trunk_ref->trunk != trunk || station_ref->station == station)
05020             continue;
05021          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
05022             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
05023             return 1;
05024          return 0;
05025       }
05026    }
05027 
05028    return 0;
05029 }

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

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

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

05243 {
05244    struct sla_station_ref *timed_out_station;
05245 
05246    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
05247       if (station == timed_out_station->station)
05248          return 1;
05249    }
05250 
05251    return 0;
05252 }

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

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

Definition at line 6065 of file app_meetme.c.

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

Referenced by sla_station_exec().

06066 {
06067    struct sla_trunk_ref *trunk_ref = NULL;
06068 
06069    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06070       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
06071          break;
06072    }
06073 
06074    return trunk_ref;
06075 }

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

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

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, sla_ringing_trunk::entry, 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().

05264 {
05265    struct sla_trunk_ref *s_trunk_ref;
05266    struct sla_ringing_trunk *ringing_trunk = NULL;
05267 
05268    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
05269       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05270          /* Make sure this is the trunk we're looking for */
05271          if (s_trunk_ref->trunk != ringing_trunk->trunk)
05272             continue;
05273 
05274          /* This trunk on the station is ringing.  But, make sure this station
05275           * didn't already time out while this trunk was ringing. */
05276          if (sla_check_timed_out_station(ringing_trunk, station))
05277             continue;
05278 
05279          if (rm)
05280             AST_LIST_REMOVE_CURRENT(entry);
05281 
05282          if (trunk_ref)
05283             *trunk_ref = s_trunk_ref;
05284 
05285          break;
05286       }
05287       AST_LIST_TRAVERSE_SAFE_END;
05288    
05289       if (ringing_trunk)
05290          break;
05291    }
05292 
05293    return ringing_trunk;
05294 }

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

Definition at line 5075 of file app_meetme.c.

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

Referenced by sla_ring_station().

05076 {
05077    struct sla_ringing_station *ringing_station;
05078 
05079    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
05080       return NULL;
05081 
05082    ringing_station->station = station;
05083    ringing_station->ring_begin = ast_tvnow();
05084 
05085    return ringing_station;
05086 }

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

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

05064 {
05065    struct sla_station_ref *station_ref;
05066 
05067    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
05068       return NULL;
05069 
05070    station_ref->station = station;
05071 
05072    return station_ref;
05073 }

static void sla_destroy ( void   )  [static]

Definition at line 6474 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_station::entry, sla, and sla_registrar.

Referenced by unload_module().

06475 {
06476    struct sla_trunk *trunk;
06477    struct sla_station *station;
06478 
06479    AST_RWLIST_WRLOCK(&sla_trunks);
06480    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
06481       destroy_trunk(trunk);
06482    AST_RWLIST_UNLOCK(&sla_trunks);
06483 
06484    AST_RWLIST_WRLOCK(&sla_stations);
06485    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
06486       destroy_station(station);
06487    AST_RWLIST_UNLOCK(&sla_stations);
06488 
06489    if (sla.thread != AST_PTHREADT_NULL) {
06490       ast_mutex_lock(&sla.lock);
06491       sla.stop = 1;
06492       ast_cond_signal(&sla.cond);
06493       ast_mutex_unlock(&sla.lock);
06494       pthread_join(sla.thread, NULL);
06495    }
06496 
06497    /* Drop any created contexts from the dialplan */
06498    ast_context_destroy(NULL, sla_registrar);
06499 
06500    ast_mutex_destroy(&sla.lock);
06501    ast_cond_destroy(&sla.cond);
06502 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 5233 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

05234 {
05235    sla_queue_event(SLA_EVENT_DIAL_STATE);
05236 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 4998 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, sla_station::entry, and sla_station::name.

Referenced by sla_station_exec().

04999 {
05000    struct sla_station *station = NULL;
05001 
05002    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
05003       if (!strcasecmp(station->name, name))
05004          break;
05005    }
05006 
05007    return station;
05008 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 4983 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, sla_trunk::entry, and sla_trunk::name.

Referenced by sla_trunk_exec().

04984 {
04985    struct sla_trunk *trunk = NULL;
04986 
04987    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04988       if (!strcasecmp(trunk->name, name))
04989          break;
04990    }
04991 
04992    return trunk;
04993 }

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

Definition at line 5482 of file app_meetme.c.

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

Referenced by sla_check_station_delay().

05484 {
05485    struct sla_trunk_ref *trunk_ref = NULL;
05486 
05487    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05488       if (trunk_ref->trunk == trunk)
05489          break;
05490    }
05491 
05492    return trunk_ref;
05493 }

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

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

References AST_LIST_TRAVERSE, sla_trunk::barge_disabled, sla_trunk_ref::entry, 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().

05040 {
05041    struct sla_trunk_ref *trunk_ref = NULL;
05042 
05043    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05044       if (strcasecmp(trunk_ref->trunk->name, name))
05045          continue;
05046 
05047       if ( (trunk_ref->trunk->barge_disabled 
05048          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
05049          (trunk_ref->trunk->hold_stations 
05050          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
05051          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
05052          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
05053       {
05054          trunk_ref = NULL;
05055       }
05056 
05057       break;
05058    }
05059 
05060    return trunk_ref;
05061 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 5296 of file app_meetme.c.

References ALL_TRUNK_REFS, answer_trunk_chan(), args, 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_lock, sla_station::dial, sla_ringing_station::entry, 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, sla_ringing_station::station, and sla_ringing_trunk::trunk.

Referenced by sla_thread().

05297 {
05298    struct sla_ringing_station *ringing_station;
05299 
05300    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05301       struct sla_trunk_ref *s_trunk_ref = NULL;
05302       struct sla_ringing_trunk *ringing_trunk = NULL;
05303       struct run_station_args args;
05304       enum ast_dial_result dial_res;
05305       pthread_t dont_care;
05306       ast_mutex_t cond_lock;
05307       ast_cond_t cond;
05308 
05309       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
05310       case AST_DIAL_RESULT_HANGUP:
05311       case AST_DIAL_RESULT_INVALID:
05312       case AST_DIAL_RESULT_FAILED:
05313       case AST_DIAL_RESULT_TIMEOUT:
05314       case AST_DIAL_RESULT_UNANSWERED:
05315          AST_LIST_REMOVE_CURRENT(entry);
05316          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
05317          break;
05318       case AST_DIAL_RESULT_ANSWERED:
05319          AST_LIST_REMOVE_CURRENT(entry);
05320          /* Find the appropriate trunk to answer. */
05321          ast_mutex_lock(&sla.lock);
05322          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
05323          ast_mutex_unlock(&sla.lock);
05324          if (!ringing_trunk) {
05325             ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
05326             break;
05327          }
05328          /* Track the channel that answered this trunk */
05329          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
05330          /* Actually answer the trunk */
05331          answer_trunk_chan(ringing_trunk->trunk->chan);
05332          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05333          /* Now, start a thread that will connect this station to the trunk.  The rest of
05334           * the code here sets up the thread and ensures that it is able to save the arguments
05335           * before they are no longer valid since they are allocated on the stack. */
05336          args.trunk_ref = s_trunk_ref;
05337          args.station = ringing_station->station;
05338          args.cond = &cond;
05339          args.cond_lock = &cond_lock;
05340          ast_free(ringing_trunk);
05341          ast_free(ringing_station);
05342          ast_mutex_init(&cond_lock);
05343          ast_cond_init(&cond, NULL);
05344          ast_mutex_lock(&cond_lock);
05345          ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
05346          ast_cond_wait(&cond, &cond_lock);
05347          ast_mutex_unlock(&cond_lock);
05348          ast_mutex_destroy(&cond_lock);
05349          ast_cond_destroy(&cond);
05350          break;
05351       case AST_DIAL_RESULT_TRYING:
05352       case AST_DIAL_RESULT_RINGING:
05353       case AST_DIAL_RESULT_PROGRESS:
05354       case AST_DIAL_RESULT_PROCEEDING:
05355          break;
05356       }
05357       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
05358          /* Queue up reprocessing ringing trunks, and then ringing stations again */
05359          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05360          sla_queue_event(SLA_EVENT_DIAL_STATE);
05361          break;
05362       }
05363    }
05364    AST_LIST_TRAVERSE_SAFE_END;
05365 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 5612 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_trunk::on_hold, sla_change_trunk_state(), SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, sla_event::station, sla_trunk_ref::trunk, and sla_event::trunk_ref.

Referenced by sla_thread().

05613 {
05614    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
05615    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
05616    ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
05617       event->station->name, event->trunk_ref->trunk->name);
05618    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
05619       INACTIVE_TRUNK_REFS, event->trunk_ref);
05620 
05621    if (event->trunk_ref->trunk->active_stations == 1) {
05622       /* The station putting it on hold is the only one on the call, so start
05623        * Music on hold to the trunk. */
05624       event->trunk_ref->trunk->on_hold = 1;
05625       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
05626    }
05627 
05628    ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
05629    event->trunk_ref->chan = NULL;
05630 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 5602 of file app_meetme.c.

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

Referenced by sla_thread().

05603 {
05604    ast_mutex_lock(&sla.lock);
05605    sla_ring_stations();
05606    ast_mutex_unlock(&sla.lock);
05607 
05608    /* Find stations that shouldn't be ringing anymore. */
05609    sla_hangup_stations();
05610 }

static void sla_hangup_stations ( void   )  [static]

Definition at line 5574 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_ringing_trunk::entry, sla_ringing_station::entry, sla, sla_ringing_station::station, sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_handle_ringing_trunk_event().

05575 {
05576    struct sla_trunk_ref *trunk_ref;
05577    struct sla_ringing_station *ringing_station;
05578 
05579    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05580       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05581          struct sla_ringing_trunk *ringing_trunk;
05582          ast_mutex_lock(&sla.lock);
05583          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05584             if (trunk_ref->trunk == ringing_trunk->trunk)
05585                break;
05586          }
05587          ast_mutex_unlock(&sla.lock);
05588          if (ringing_trunk)
05589             break;
05590       }
05591       if (!trunk_ref) {
05592          AST_LIST_REMOVE_CURRENT(entry);
05593          ast_dial_join(ringing_station->station->dial);
05594          ast_dial_destroy(ringing_station->station->dial);
05595          ringing_station->station->dial = NULL;
05596          ast_free(ringing_station);
05597       }
05598    }
05599    AST_LIST_TRAVERSE_SAFE_END
05600 }

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

Definition at line 1598 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01599 {
01600    const char *hold = "Unknown";
01601 
01602    switch (hold_access) {
01603    case SLA_HOLD_OPEN:
01604       hold = "Open";
01605       break;
01606    case SLA_HOLD_PRIVATE:
01607       hold = "Private";
01608    default:
01609       break;
01610    }
01611 
01612    return hold;
01613 }

static int sla_load_config ( int  reload  )  [static]

Definition at line 6754 of file app_meetme.c.

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

Referenced by load_config(), and sla_check_reload().

06755 {
06756    struct ast_config *cfg;
06757    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06758    const char *cat = NULL;
06759    int res = 0;
06760    const char *val;
06761 
06762    if (!reload) {
06763       ast_mutex_init(&sla.lock);
06764       ast_cond_init(&sla.cond, NULL);
06765    }
06766 
06767    if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
06768       return 0; /* Treat no config as normal */
06769    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06770       return 0;
06771    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06772       ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format.  Aborting.\n");
06773       return 0;
06774    }
06775 
06776    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
06777       sla.attempt_callerid = ast_true(val);
06778 
06779    while ((cat = ast_category_browse(cfg, cat)) && !res) {
06780       const char *type;
06781       if (!strcasecmp(cat, "general"))
06782          continue;
06783       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
06784          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
06785             SLA_CONFIG_FILE);
06786          continue;
06787       }
06788       if (!strcasecmp(type, "trunk"))
06789          res = sla_build_trunk(cfg, cat);
06790       else if (!strcasecmp(type, "station"))
06791          res = sla_build_station(cfg, cat);
06792       else {
06793          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
06794             SLA_CONFIG_FILE, type);
06795       }
06796    }
06797 
06798    ast_config_destroy(cfg);
06799 
06800    /* Even if we don't have any stations, we may after a reload and we need to
06801     * be able to process the SLA_EVENT_RELOAD event in that case */
06802    if (sla.thread == AST_PTHREADT_NULL && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_trunks))) {
06803       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
06804    }
06805 
06806    return res;
06807 }

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

05791 {
05792    unsigned int timeout = UINT_MAX;
05793    struct timeval wait;
05794    unsigned int change_made = 0;
05795 
05796    /* Check for ring timeouts on ringing trunks */
05797    if (sla_calc_trunk_timeouts(&timeout))
05798       change_made = 1;
05799 
05800    /* Check for ring timeouts on ringing stations */
05801    if (sla_calc_station_timeouts(&timeout))
05802       change_made = 1;
05803 
05804    /* Check for station ring delays */
05805    if (sla_calc_station_delays(&timeout))
05806       change_made = 1;
05807 
05808    /* queue reprocessing of ringing trunks */
05809    if (change_made)
05810       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
05811 
05812    /* No timeout */
05813    if (timeout == UINT_MAX)
05814       return 0;
05815 
05816    if (ts) {
05817       wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
05818       ts->tv_sec = wait.tv_sec;
05819       ts->tv_nsec = wait.tv_usec * 1000;
05820    }
05821 
05822    return 1;
05823 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

Definition at line 1913 of file app_meetme.c.

References sla_queue_event_full().

Referenced by load_config(), queue_ringing_trunk(), sla_dial_state_callback(), sla_handle_dial_state_event(), sla_station_exec(), and sla_trunk_exec().

01914 {
01915    sla_queue_event_full(type, NULL, NULL, 1);
01916 }

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 1919 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, announce_listitem::entry, LOG_ERROR, sla_trunk::name, sla_queue_event_full(), strsep(), sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by conf_run().

01921 {
01922    struct sla_station *station;
01923    struct sla_trunk_ref *trunk_ref = NULL;
01924    char *trunk_name;
01925 
01926    trunk_name = ast_strdupa(conf->confno);
01927    strsep(&trunk_name, "_");
01928    if (ast_strlen_zero(trunk_name)) {
01929       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01930       return;
01931    }
01932 
01933    AST_RWLIST_RDLOCK(&sla_stations);
01934    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01935       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01936          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01937             break;
01938       }
01939       if (trunk_ref)
01940          break;
01941    }
01942    AST_RWLIST_UNLOCK(&sla_stations);
01943 
01944    if (!trunk_ref) {
01945       ast_debug(1, "Trunk not found for event!\n");
01946       return;
01947    }
01948 
01949    sla_queue_event_full(type, trunk_ref, station, 1);
01950 }

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

References ast_calloc, ast_cond_signal, AST_LIST_INSERT_TAIL, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, announce_listitem::entry, sla, sla_event::station, and sla_event::trunk_ref.

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

01883 {
01884    struct sla_event *event;
01885 
01886    if (sla.thread == AST_PTHREADT_NULL) {
01887       return;
01888    }
01889 
01890    if (!(event = ast_calloc(1, sizeof(*event))))
01891       return;
01892 
01893    event->type = type;
01894    event->trunk_ref = trunk_ref;
01895    event->station = station;
01896 
01897    if (!lock) {
01898       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01899       return;
01900    }
01901 
01902    ast_mutex_lock(&sla.lock);
01903    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01904    ast_cond_signal(&sla.cond);
01905    ast_mutex_unlock(&sla.lock);
01906 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1908 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01909 {
01910    sla_queue_event_full(type, NULL, NULL, 0);
01911 }

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 5408 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::entry, sla, sla_create_ringing_station(), sla_dial_state_callback(), sla_failed_station::station, strsep(), and sla_ringing_trunk::trunk.

Referenced by sla_ring_stations().

05409 {
05410    char *tech, *tech_data;
05411    struct ast_dial *dial;
05412    struct sla_ringing_station *ringing_station;
05413    enum ast_dial_result res;
05414    int caller_is_saved;
05415    struct ast_party_caller caller;
05416 
05417    if (!(dial = ast_dial_create()))
05418       return -1;
05419 
05420    ast_dial_set_state_callback(dial, sla_dial_state_callback);
05421    tech_data = ast_strdupa(station->device);
05422    tech = strsep(&tech_data, "/");
05423 
05424    if (ast_dial_append(dial, tech, tech_data) == -1) {
05425       ast_dial_destroy(dial);
05426       return -1;
05427    }
05428 
05429    /* Do we need to save off the caller ID data? */
05430    caller_is_saved = 0;
05431    if (!sla.attempt_callerid) {
05432       caller_is_saved = 1;
05433       caller = ringing_trunk->trunk->chan->caller;
05434       ast_party_caller_init(&ringing_trunk->trunk->chan->caller);
05435    }
05436 
05437    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
05438    
05439    /* Restore saved caller ID */
05440    if (caller_is_saved) {
05441       ast_party_caller_free(&ringing_trunk->trunk->chan->caller);
05442       ringing_trunk->trunk->chan->caller = caller;
05443    }
05444    
05445    if (res != AST_DIAL_RESULT_TRYING) {
05446       struct sla_failed_station *failed_station;
05447       ast_dial_destroy(dial);
05448       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
05449          return -1;
05450       failed_station->station = station;
05451       failed_station->last_try = ast_tvnow();
05452       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
05453       return -1;
05454    }
05455    if (!(ringing_station = sla_create_ringing_station(station))) {
05456       ast_dial_join(dial);
05457       ast_dial_destroy(dial);
05458       return -1;
05459    }
05460 
05461    station->dial = dial;
05462 
05463    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
05464 
05465    return 0;
05466 }

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

References AST_LIST_TRAVERSE, sla_ringing_trunk::entry, 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().

05534 {
05535    struct sla_station_ref *station_ref;
05536    struct sla_ringing_trunk *ringing_trunk;
05537 
05538    /* Make sure that every station that uses at least one of the ringing
05539     * trunks, is ringing. */
05540    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05541       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
05542          int time_left;
05543 
05544          /* Is this station already ringing? */
05545          if (sla_check_ringing_station(station_ref->station))
05546             continue;
05547 
05548          /* Is this station already in a call? */
05549          if (sla_check_inuse_station(station_ref->station))
05550             continue;
05551 
05552          /* Did we fail to dial this station earlier?  If so, has it been
05553           * a minute since we tried? */
05554          if (sla_check_failed_station(station_ref->station))
05555             continue;
05556 
05557          /* If this station already timed out while this trunk was ringing,
05558           * do not dial it again for this ringing trunk. */
05559          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
05560             continue;
05561 
05562          /* Check for a ring delay in progress */
05563          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
05564          if (time_left != INT_MAX && time_left > 0)
05565             continue;
05566 
05567          /* It is time to make this station begin to ring.  Do it! */
05568          sla_ring_station(ringing_trunk, station_ref->station);
05569       }
05570    }
05571    /* Now, all of the stations that should be ringing, are ringing. */
05572 }

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

Definition at line 1680 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, announce_listitem::entry, 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.

01681 {
01682    const struct sla_station *station;
01683 
01684    switch (cmd) {
01685    case CLI_INIT:
01686       e->command = "sla show stations";
01687       e->usage =
01688          "Usage: sla show stations\n"
01689          "       This will list all stations defined in sla.conf\n";
01690       return NULL;
01691    case CLI_GENERATE:
01692       return NULL;
01693    }
01694 
01695    ast_cli(a->fd, "\n" 
01696                "=============================================================\n"
01697                "=== Configured SLA Stations =================================\n"
01698                "=============================================================\n"
01699                "===\n");
01700    AST_RWLIST_RDLOCK(&sla_stations);
01701    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01702       struct sla_trunk_ref *trunk_ref;
01703       char ring_timeout[16] = "(none)";
01704       char ring_delay[16] = "(none)";
01705       if (station->ring_timeout) {
01706          snprintf(ring_timeout, sizeof(ring_timeout), 
01707             "%u", station->ring_timeout);
01708       }
01709       if (station->ring_delay) {
01710          snprintf(ring_delay, sizeof(ring_delay), 
01711             "%u", station->ring_delay);
01712       }
01713       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01714                   "=== Station Name:    %s\n"
01715                   "=== ==> Device:      %s\n"
01716                   "=== ==> AutoContext: %s\n"
01717                   "=== ==> RingTimeout: %s\n"
01718                   "=== ==> RingDelay:   %s\n"
01719                   "=== ==> HoldAccess:  %s\n"
01720                   "=== ==> Trunks ...\n",
01721                   station->name, station->device,
01722                   S_OR(station->autocontext, "(none)"), 
01723                   ring_timeout, ring_delay,
01724                   sla_hold_str(station->hold_access));
01725       AST_RWLIST_RDLOCK(&sla_trunks);
01726       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01727          if (trunk_ref->ring_timeout) {
01728             snprintf(ring_timeout, sizeof(ring_timeout),
01729                "%u", trunk_ref->ring_timeout);
01730          } else
01731             strcpy(ring_timeout, "(none)");
01732          if (trunk_ref->ring_delay) {
01733             snprintf(ring_delay, sizeof(ring_delay),
01734                "%u", trunk_ref->ring_delay);
01735          } else
01736             strcpy(ring_delay, "(none)");
01737             ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
01738                      "===       ==> State:       %s\n"
01739                      "===       ==> RingTimeout: %s\n"
01740                      "===       ==> RingDelay:   %s\n",
01741                      trunk_ref->trunk->name,
01742                      trunkstate2str(trunk_ref->state),
01743                      ring_timeout, ring_delay);
01744       }
01745       AST_RWLIST_UNLOCK(&sla_trunks);
01746       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01747                   "===\n");
01748    }
01749    AST_RWLIST_UNLOCK(&sla_stations);
01750    ast_cli(a->fd, "============================================================\n"
01751                "\n");
01752 
01753    return CLI_SUCCESS;
01754 }

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

Definition at line 1615 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, announce_listitem::entry, 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.

01616 {
01617    const struct sla_trunk *trunk;
01618 
01619    switch (cmd) {
01620    case CLI_INIT:
01621       e->command = "sla show trunks";
01622       e->usage =
01623          "Usage: sla show trunks\n"
01624          "       This will list all trunks defined in sla.conf\n";
01625       return NULL;
01626    case CLI_GENERATE:
01627       return NULL;
01628    }
01629 
01630    ast_cli(a->fd, "\n"
01631                "=============================================================\n"
01632                "=== Configured SLA Trunks ===================================\n"
01633                "=============================================================\n"
01634                "===\n");
01635    AST_RWLIST_RDLOCK(&sla_trunks);
01636    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01637       struct sla_station_ref *station_ref;
01638       char ring_timeout[16] = "(none)";
01639       if (trunk->ring_timeout)
01640          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01641       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01642                   "=== Trunk Name:       %s\n"
01643                   "=== ==> Device:       %s\n"
01644                   "=== ==> AutoContext:  %s\n"
01645                   "=== ==> RingTimeout:  %s\n"
01646                   "=== ==> BargeAllowed: %s\n"
01647                   "=== ==> HoldAccess:   %s\n"
01648                   "=== ==> Stations ...\n",
01649                   trunk->name, trunk->device, 
01650                   S_OR(trunk->autocontext, "(none)"), 
01651                   ring_timeout,
01652                   trunk->barge_disabled ? "No" : "Yes",
01653                   sla_hold_str(trunk->hold_access));
01654       AST_RWLIST_RDLOCK(&sla_stations);
01655       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01656          ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
01657       AST_RWLIST_UNLOCK(&sla_stations);
01658       ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
01659    }
01660    AST_RWLIST_UNLOCK(&sla_trunks);
01661    ast_cli(a->fd, "=============================================================\n\n");
01662 
01663    return CLI_SUCCESS;
01664 }

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

Definition at line 6398 of file app_meetme.c.

References AST_DEVICE_INVALID, ast_device_state(), AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_strdupa, sla_trunk_ref::entry, 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().

06399 {
06400    char *buf, *station_name, *trunk_name;
06401    struct sla_station *station;
06402    struct sla_trunk_ref *trunk_ref;
06403    enum ast_device_state res = AST_DEVICE_INVALID;
06404 
06405    trunk_name = buf = ast_strdupa(data);
06406    station_name = strsep(&trunk_name, "_");
06407 
06408    AST_RWLIST_RDLOCK(&sla_stations);
06409    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
06410       if (strcasecmp(station_name, station->name))
06411          continue;
06412       AST_RWLIST_RDLOCK(&sla_trunks);
06413       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06414          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
06415             break;
06416       }
06417       if (!trunk_ref) {
06418          AST_RWLIST_UNLOCK(&sla_trunks);
06419          break;
06420       }
06421       res = sla_state_to_devstate(trunk_ref->state);
06422       AST_RWLIST_UNLOCK(&sla_trunks);
06423    }
06424    AST_RWLIST_UNLOCK(&sla_stations);
06425 
06426    if (res == AST_DEVICE_INVALID) {
06427       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
06428          trunk_name, station_name);
06429    }
06430 
06431    return res;
06432 }

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

Definition at line 5088 of file app_meetme.c.

References AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_UNKNOWN, SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, and SLA_TRUNK_STATE_UP.

Referenced by sla_change_trunk_state(), and sla_state().

05089 {
05090    switch (state) {
05091    case SLA_TRUNK_STATE_IDLE:
05092       return AST_DEVICE_NOT_INUSE;
05093    case SLA_TRUNK_STATE_RINGING:
05094       return AST_DEVICE_RINGING;
05095    case SLA_TRUNK_STATE_UP:
05096       return AST_DEVICE_INUSE;
05097    case SLA_TRUNK_STATE_ONHOLD:
05098    case SLA_TRUNK_STATE_ONHOLD_BYME:
05099       return AST_DEVICE_ONHOLD;
05100    }
05101 
05102    return AST_DEVICE_UNKNOWN;
05103 }

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

Definition at line 6077 of file app_meetme.c.

References sla_trunk::active_stations, admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), args, 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, ast_conference::chan, dial_trunk_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dial_trunk(), dispose_conf(), sla_ringing_trunk::entry, 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, dial_trunk_args::station, strsep(), sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.

Referenced by load_module().

06078 {
06079    char *station_name, *trunk_name;
06080    struct sla_station *station;
06081    struct sla_trunk_ref *trunk_ref = NULL;
06082    char conf_name[MAX_CONFNUM];
06083    struct ast_flags64 conf_flags = { 0 };
06084    struct ast_conference *conf;
06085 
06086    if (ast_strlen_zero(data)) {
06087       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
06088       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06089       return 0;
06090    }
06091 
06092    trunk_name = ast_strdupa(data);
06093    station_name = strsep(&trunk_name, "_");
06094 
06095    if (ast_strlen_zero(station_name)) {
06096       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
06097       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06098       return 0;
06099    }
06100 
06101    AST_RWLIST_RDLOCK(&sla_stations);
06102    station = sla_find_station(station_name);
06103    if (station)
06104       ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
06105    AST_RWLIST_UNLOCK(&sla_stations);
06106 
06107    if (!station) {
06108       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
06109       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06110       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06111       return 0;
06112    }
06113 
06114    AST_RWLIST_RDLOCK(&sla_trunks);
06115    if (!ast_strlen_zero(trunk_name)) {
06116       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
06117    } else
06118       trunk_ref = sla_choose_idle_trunk(station);
06119    AST_RWLIST_UNLOCK(&sla_trunks);
06120 
06121    if (!trunk_ref) {
06122       if (ast_strlen_zero(trunk_name))
06123          ast_log(LOG_NOTICE, "No trunks available for call.\n");
06124       else {
06125          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
06126             "'%s' due to access controls.\n", trunk_name);
06127       }
06128       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
06129       ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06130       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06131       return 0;
06132    }
06133 
06134    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
06135       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
06136          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06137       else {
06138          trunk_ref->state = SLA_TRUNK_STATE_UP;
06139          ast_devstate_changed(AST_DEVICE_INUSE, 
06140             "SLA:%s_%s", station->name, trunk_ref->trunk->name);
06141       }
06142    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
06143       struct sla_ringing_trunk *ringing_trunk;
06144 
06145       ast_mutex_lock(&sla.lock);
06146       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
06147          if (ringing_trunk->trunk == trunk_ref->trunk) {
06148             AST_LIST_REMOVE_CURRENT(entry);
06149             break;
06150          }
06151       }
06152       AST_LIST_TRAVERSE_SAFE_END
06153       ast_mutex_unlock(&sla.lock);
06154 
06155       if (ringing_trunk) {
06156          answer_trunk_chan(ringing_trunk->trunk->chan);
06157          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06158 
06159          free(ringing_trunk);
06160 
06161          /* Queue up reprocessing ringing trunks, and then ringing stations again */
06162          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06163          sla_queue_event(SLA_EVENT_DIAL_STATE);
06164       }
06165    }
06166 
06167    trunk_ref->chan = chan;
06168 
06169    if (!trunk_ref->trunk->chan) {
06170       ast_mutex_t cond_lock;
06171       ast_cond_t cond;
06172       pthread_t dont_care;
06173       struct dial_trunk_args args = {
06174          .trunk_ref = trunk_ref,
06175          .station = station,
06176          .cond_lock = &cond_lock,
06177          .cond = &cond,
06178       };
06179       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06180       /* Create a thread to dial the trunk and dump it into the conference.
06181        * However, we want to wait until the trunk has been dialed and the
06182        * conference is created before continuing on here. */
06183       ast_autoservice_start(chan);
06184       ast_mutex_init(&cond_lock);
06185       ast_cond_init(&cond, NULL);
06186       ast_mutex_lock(&cond_lock);
06187       ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
06188       ast_cond_wait(&cond, &cond_lock);
06189       ast_mutex_unlock(&cond_lock);
06190       ast_mutex_destroy(&cond_lock);
06191       ast_cond_destroy(&cond);
06192       ast_autoservice_stop(chan);
06193       if (!trunk_ref->trunk->chan) {
06194          ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
06195          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
06196          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06197          trunk_ref->chan = NULL;
06198          ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06199          sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06200          return 0;
06201       }
06202    }
06203 
06204    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
06205       trunk_ref->trunk->on_hold) {
06206       trunk_ref->trunk->on_hold = 0;
06207       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
06208       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06209    }
06210 
06211    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
06212    ast_set_flag64(&conf_flags, 
06213       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
06214    ast_answer(chan);
06215    conf = build_conf(conf_name, "", "", 0, 0, 1, chan, NULL);
06216    if (conf) {
06217       conf_run(chan, conf, &conf_flags, NULL);
06218       dispose_conf(conf);
06219       conf = NULL;
06220    }
06221    trunk_ref->chan = NULL;
06222    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
06223       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
06224       strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
06225       admin_exec(NULL, conf_name);
06226       trunk_ref->trunk->hold_stations = 0;
06227       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06228    }
06229    
06230    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
06231 
06232    ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06233    sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06234 
06235    return 0;
06236 }

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

Definition at line 5198 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_station_ref::entry, 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().

05200 {
05201    struct sla_ringing_trunk *ringing_trunk;
05202    struct sla_trunk_ref *trunk_ref;
05203    struct sla_station_ref *station_ref;
05204 
05205    ast_dial_join(ringing_station->station->dial);
05206    ast_dial_destroy(ringing_station->station->dial);
05207    ringing_station->station->dial = NULL;
05208 
05209    if (hangup == SLA_STATION_HANGUP_NORMAL)
05210       goto done;
05211 
05212    /* If the station is being hung up because of a timeout, then add it to the
05213     * list of timed out stations on each of the ringing trunks.  This is so
05214     * that when doing further processing to figure out which stations should be
05215     * ringing, which trunk to answer, determining timeouts, etc., we know which
05216     * ringing trunks we should ignore. */
05217    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05218       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05219          if (ringing_trunk->trunk == trunk_ref->trunk)
05220             break;
05221       }
05222       if (!trunk_ref)
05223          continue;
05224       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
05225          continue;
05226       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
05227    }
05228 
05229 done:
05230    ast_free(ringing_station);
05231 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 5183 of file app_meetme.c.

References admin_exec(), ALL_TRUNK_REFS, ast_free, AST_LIST_REMOVE_HEAD, sla_station_ref::entry, 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().

05184 {
05185    char buf[80];
05186    struct sla_station_ref *station_ref;
05187 
05188    snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
05189    admin_exec(NULL, buf);
05190    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05191 
05192    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
05193       ast_free(station_ref);
05194 
05195    ast_free(ringing_trunk);
05196 }

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

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

05884 {
05885    struct sla_failed_station *failed_station;
05886    struct sla_ringing_station *ringing_station;
05887 
05888    ast_mutex_lock(&sla.lock);
05889 
05890    while (!sla.stop) {
05891       struct sla_event *event;
05892       struct timespec ts = { 0, };
05893       unsigned int have_timeout = 0;
05894 
05895       if (AST_LIST_EMPTY(&sla.event_q)) {
05896          if ((have_timeout = sla_process_timers(&ts)))
05897             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
05898          else
05899             ast_cond_wait(&sla.cond, &sla.lock);
05900          if (sla.stop)
05901             break;
05902       }
05903 
05904       if (have_timeout)
05905          sla_process_timers(NULL);
05906 
05907       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
05908          ast_mutex_unlock(&sla.lock);
05909          switch (event->type) {
05910          case SLA_EVENT_HOLD:
05911             sla_handle_hold_event(event);
05912             break;
05913          case SLA_EVENT_DIAL_STATE:
05914             sla_handle_dial_state_event();
05915             break;
05916          case SLA_EVENT_RINGING_TRUNK:
05917             sla_handle_ringing_trunk_event();
05918             break;
05919          case SLA_EVENT_RELOAD:
05920             sla.reload = 1;
05921          case SLA_EVENT_CHECK_RELOAD:
05922             break;
05923          }
05924          ast_free(event);
05925          ast_mutex_lock(&sla.lock);
05926       }
05927 
05928       if (sla.reload) {
05929          sla_check_reload();
05930       }
05931    }
05932 
05933    ast_mutex_unlock(&sla.lock);
05934 
05935    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
05936       ast_free(ringing_station);
05937 
05938    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
05939       ast_free(failed_station);
05940 
05941    return NULL;
05942 }

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

Definition at line 6284 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, OPT_ARG_ARRAY_SIZE, OPT_ARG_MOH_CLASS, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), queue_ringing_trunk(), sla_trunk::ref_count, sla, sla_change_trunk_state(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), SLA_TRUNK_OPT_ARG_ARRAY_SIZE, SLA_TRUNK_OPT_ARG_MOH_CLASS, SLA_TRUNK_OPT_MOH, sla_trunk_opts, SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by load_module().

06285 {
06286    char conf_name[MAX_CONFNUM];
06287    struct ast_conference *conf;
06288    struct ast_flags64 conf_flags = { 0 };
06289    struct sla_trunk *trunk;
06290    struct sla_ringing_trunk *ringing_trunk;
06291    AST_DECLARE_APP_ARGS(args,
06292       AST_APP_ARG(trunk_name);
06293       AST_APP_ARG(options);
06294    );
06295    char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
06296    char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
06297    struct ast_flags opt_flags = { 0 };
06298    char *parse;
06299 
06300    if (ast_strlen_zero(data)) {
06301       ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
06302       return -1;
06303    }
06304 
06305    parse = ast_strdupa(data);
06306    AST_STANDARD_APP_ARGS(args, parse);
06307    if (args.argc == 2) {
06308       if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
06309          ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
06310          return -1;
06311       }
06312    }
06313 
06314    AST_RWLIST_RDLOCK(&sla_trunks);
06315    trunk = sla_find_trunk(args.trunk_name);
06316    if (trunk)
06317       ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
06318    AST_RWLIST_UNLOCK(&sla_trunks);
06319 
06320    if (!trunk) {
06321       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
06322       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06323       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06324       return 0;
06325    }
06326 
06327    if (trunk->chan) {
06328       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
06329          args.trunk_name);
06330       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06331       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06332       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06333       return 0;
06334    }
06335 
06336    trunk->chan = chan;
06337 
06338    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
06339       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06340       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06341       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06342       return 0;
06343    }
06344 
06345    snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
06346    conf = build_conf(conf_name, "", "", 1, 1, 1, chan, NULL);
06347    if (!conf) {
06348       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06349       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06350       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06351       return 0;
06352    }
06353    ast_set_flag64(&conf_flags, 
06354       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
06355 
06356    if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
06357       ast_indicate(chan, -1);
06358       ast_set_flag64(&conf_flags, CONFFLAG_MOH);
06359       conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
06360    } else
06361       ast_indicate(chan, AST_CONTROL_RINGING);
06362 
06363    conf_run(chan, conf, &conf_flags, opts);
06364    dispose_conf(conf);
06365    conf = NULL;
06366    trunk->chan = NULL;
06367    trunk->on_hold = 0;
06368 
06369    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06370 
06371    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
06372       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
06373 
06374    /* Remove the entry from the list of ringing trunks if it is still there. */
06375    ast_mutex_lock(&sla.lock);
06376    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
06377       if (ringing_trunk->trunk == trunk) {
06378          AST_LIST_REMOVE_CURRENT(entry);
06379          break;
06380       }
06381    }
06382    AST_LIST_TRAVERSE_SAFE_END;
06383    ast_mutex_unlock(&sla.lock);
06384    if (ringing_trunk) {
06385       ast_free(ringing_trunk);
06386       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
06387       /* Queue reprocessing of ringing trunks to make stations stop ringing
06388        * that shouldn't be ringing after this trunk stopped. */
06389       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06390    }
06391 
06392    ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06393    sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06394 
06395    return 0;
06396 }

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

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

01667 {
01668 #define S(e) case e: return # e;
01669    switch (state) {
01670    S(SLA_TRUNK_STATE_IDLE)
01671    S(SLA_TRUNK_STATE_RINGING)
01672    S(SLA_TRUNK_STATE_UP)
01673    S(SLA_TRUNK_STATE_ONHOLD)
01674    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01675    }
01676    return "Uknown State";
01677 #undef S
01678 }

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

Definition at line 1082 of file app_meetme.c.

References set_listen_volume(), tweak_volume(), and user.

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

01083 {
01084    tweak_volume(&user->listen, action);
01085    /* attempt to make the adjustment in the channel driver;
01086       if successful, don't adjust in the frame reading routine
01087    */
01088    if (!set_listen_volume(user, user->listen.desired))
01089       user->listen.actual = 0;
01090    else
01091       user->listen.actual = user->listen.desired;
01092 }

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

Definition at line 1070 of file app_meetme.c.

References set_talk_volume(), tweak_volume(), and user.

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

01071 {
01072    tweak_volume(&user->talk, action);
01073    /* attempt to make the adjustment in the channel driver;
01074       if successful, don't adjust in the frame reading routine
01075    */
01076    if (!set_talk_volume(user, user->talk.desired))
01077       user->talk.actual = 0;
01078    else
01079       user->talk.actual = user->talk.desired;
01080 }

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

Definition at line 1035 of file app_meetme.c.

References volume::desired, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

01036 {
01037    switch (action) {
01038    case VOL_UP:
01039       switch (vol->desired) { 
01040       case 5:
01041          break;
01042       case 0:
01043          vol->desired = 2;
01044          break;
01045       case -2:
01046          vol->desired = 0;
01047          break;
01048       default:
01049          vol->desired++;
01050          break;
01051       }
01052       break;
01053    case VOL_DOWN:
01054       switch (vol->desired) {
01055       case -5:
01056          break;
01057       case 2:
01058          vol->desired = 0;
01059          break;
01060       case 0:
01061          vol->desired = -2;
01062          break;
01063       default:
01064          vol->desired--;
01065          break;
01066       }
01067    }
01068 }

static int unload_module ( void   )  [static]

Definition at line 7076 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(), cli_meetme, meetme_info_acf, and sla_destroy().

07077 {
07078    int res = 0;
07079    
07080    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07081    res = ast_manager_unregister("MeetmeMute");
07082    res |= ast_manager_unregister("MeetmeUnmute");
07083    res |= ast_manager_unregister("MeetmeList");
07084    res |= ast_unregister_application(app4);
07085    res |= ast_unregister_application(app3);
07086    res |= ast_unregister_application(app2);
07087    res |= ast_unregister_application(app);
07088    res |= ast_unregister_application(slastation_app);
07089    res |= ast_unregister_application(slatrunk_app);
07090 
07091 #ifdef TEST_FRAMEWORK
07092    AST_TEST_UNREGISTER(test_meetme_data_provider);
07093 #endif
07094    ast_data_unregister(NULL);
07095 
07096    ast_devstate_prov_del("Meetme");
07097    ast_devstate_prov_del("SLA");
07098    
07099    sla_destroy();
07100    
07101    res |= ast_custom_function_unregister(&meetme_info_acf);
07102    ast_unload_realtime("meetme");
07103 
07104    return res;
07105 }

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

Definition at line 6927 of file app_meetme.c.

References ast_channel_data_add_structure(), ast_data_add_int(), ast_data_add_node(), ast_data_add_structure, and user.

Referenced by meetme_data_provider_get().

06928 {
06929    struct ast_data *data_meetme_user;
06930    struct ast_data *data_meetme_user_channel;
06931    struct ast_data *data_meetme_user_volume;
06932 
06933    struct ast_conf_user *user = obj;
06934    struct ast_data *data_meetme_users = arg;
06935 
06936    data_meetme_user = ast_data_add_node(data_meetme_users, "user");
06937    if (!data_meetme_user) {
06938       return 0;
06939    }
06940    /* user structure */
06941    ast_data_add_structure(ast_conf_user, data_meetme_user, user);
06942 
06943    /* user's channel */
06944    data_meetme_user_channel = ast_data_add_node(data_meetme_user, "channel");
06945    if (!data_meetme_user_channel) {
06946       return 0;
06947    }
06948 
06949    ast_channel_data_add_structure(data_meetme_user_channel, user->chan, 1);
06950 
06951    /* volume structure */
06952    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "listen-volume");
06953    if (!data_meetme_user_volume) {
06954       return 0;
06955    }
06956    ast_data_add_int(data_meetme_user_volume, "desired", user->listen.desired);
06957    ast_data_add_int(data_meetme_user_volume, "actual", user->listen.actual);
06958 
06959    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "talk-volume");
06960    if (!data_meetme_user_volume) {
06961       return 0;
06962    }
06963    ast_data_add_int(data_meetme_user_volume, "desired", user->talk.desired);
06964    ast_data_add_int(data_meetme_user_volume, "actual", user->talk.actual);
06965 
06966    return 0;
06967 }

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

Definition at line 4465 of file app_meetme.c.

References CMP_MATCH, CMP_STOP, and user.

Referenced by channel_admin_exec().

04466 {
04467    struct ast_conf_user *user = obj;
04468    const char *channel = args;
04469 
04470    if (!strcmp(user->chan->name, channel)) {
04471       return (CMP_MATCH | CMP_STOP);
04472    }
04473 
04474    return 0;
04475 }

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

Definition at line 4437 of file app_meetme.c.

References tweak_listen_volume(), and user.

Referenced by admin_exec().

04438 {
04439    struct ast_conf_user *user = obj;
04440    tweak_listen_volume(user, VOL_DOWN);
04441    return 0;
04442 }

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

Definition at line 4430 of file app_meetme.c.

References tweak_listen_volume(), user, and VOL_UP.

Referenced by admin_exec().

04431 {
04432    struct ast_conf_user *user = obj;
04433    tweak_listen_volume(user, VOL_UP);
04434    return 0;
04435 }

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

Definition at line 1148 of file app_meetme.c.

References user.

Referenced by admin_exec(), and conf_run().

01149 {
01150    struct ast_conf_user *user = obj;
01151    int *max_no = arg;
01152 
01153    if (user->user_no > *max_no) {
01154       *max_no = user->user_no;
01155    }
01156 
01157    return 0;
01158 }

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

Definition at line 1136 of file app_meetme.c.

References CMP_MATCH, CMP_STOP, user, and ast_conf_user::user_no.

Referenced by build_conf().

01137 {
01138    struct ast_conf_user *user = obj;
01139    int *user_no = arg;
01140 
01141    if (user->user_no == *user_no) {
01142       return (CMP_MATCH | CMP_STOP);
01143    }
01144 
01145    return 0;
01146 }

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

Definition at line 4458 of file app_meetme.c.

References reset_volumes(), and user.

Referenced by admin_exec().

04459 {
04460    struct ast_conf_user *user = obj;
04461    reset_volumes(user);
04462    return 0;
04463 }

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

Definition at line 2155 of file app_meetme.c.

References ADMINFLAG_KICKME, ast_test_flag64, CONFFLAG_ADMIN, and user.

Referenced by admin_exec(), and conf_run().

02156 {
02157    struct ast_conf_user *user = obj;
02158    /* actual pointer contents of check_admin_arg is irrelevant */
02159 
02160    if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
02161       user->adminflags |= ADMINFLAG_KICKME;
02162    }
02163    return 0;
02164 }

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

Definition at line 2177 of file app_meetme.c.

References ADMINFLAG_MUTED, ast_test_flag64, CONFFLAG_ADMIN, and user.

Referenced by admin_exec(), and conf_run().

02178 {
02179    struct ast_conf_user *user = obj;
02180    /* actual pointer contents of check_admin_arg is irrelevant */
02181 
02182    if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
02183       user->adminflags |= ADMINFLAG_MUTED;
02184    }
02185    return 0;
02186 }

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

Definition at line 2166 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_test_flag64, CONFFLAG_ADMIN, and user.

Referenced by admin_exec(), and conf_run().

02167 {
02168    struct ast_conf_user *user = obj;
02169    /* actual pointer contents of check_admin_arg is irrelevant */
02170 
02171    if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
02172       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
02173    }
02174    return 0;
02175 }

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

Definition at line 4451 of file app_meetme.c.

References tweak_talk_volume(), and user.

Referenced by admin_exec().

04452 {
04453    struct ast_conf_user *user = obj;
04454    tweak_talk_volume(user, VOL_DOWN);
04455    return 0;
04456 }

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

Definition at line 4444 of file app_meetme.c.

References tweak_talk_volume(), user, and VOL_UP.

Referenced by admin_exec().

04445 {
04446    struct ast_conf_user *user = obj;
04447    tweak_talk_volume(user, VOL_UP);
04448    return 0;
04449 }


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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, } [static]

Definition at line 7151 of file app_meetme.c.

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

Definition at line 655 of file app_meetme.c.

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

Definition at line 656 of file app_meetme.c.

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

Definition at line 657 of file app_meetme.c.

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

Definition at line 658 of file app_meetme.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 7151 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 938 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 947 of file app_meetme.c.

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1756 of file app_meetme.c.

Referenced by load_module(), and unload_module().

ast_cond_t cond

Definition at line 929 of file app_meetme.c.

Referenced by _macro_exec(), gosubif_exec(), and smdi_message_wait().

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

Definition at line 740 of file app_meetme.c.

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

int earlyalert [static]

Definition at line 665 of file app_meetme.c.

int endalert [static]

Definition at line 666 of file app_meetme.c.

struct { ... } event_q

int extendby [static]

Definition at line 667 of file app_meetme.c.

struct { ... } failed_stations

struct sla_event* first

Definition at line 934 of file app_meetme.c.

struct sla_failed_station* first

Definition at line 933 of file app_meetme.c.

struct sla_ringing_station* first

Definition at line 932 of file app_meetme.c.

struct sla_ringing_trunk* first

Definition at line 931 of file app_meetme.c.

Referenced by ast_fax_caps_to_str(), ast_format_str_reduce(), ast_print_group(), ast_xmldoc_build_seealso(), cdr_handler(), check_goto(), gen_prios(), generate_filenames_string(), generic_thread_loop(), get_goto_target(), h261_encap(), h263_encap(), h263p_encap(), h264_encap(), listfilter(), log_jack_status(), mpeg4_encap(), multiplexed_thread_function(), npval2(), odbc_log(), pgsql_log(), realtime_update2_handler(), realtimefield_read(), update2_curl(), update2_pgsql(), update2_prepare(), xmldoc_get_syntax_cmd(), and xmldoc_parse_cmd_enumlist().

int fuzzystart [static]

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

struct sla_event* last

Definition at line 934 of file app_meetme.c.

struct sla_failed_station* last

Definition at line 933 of file app_meetme.c.

struct sla_ringing_station* last

Definition at line 932 of file app_meetme.c.

struct sla_ringing_trunk* last

Definition at line 931 of file app_meetme.c.

Referenced by add_extensions(), aji_handle_presence(), apply_outgoing(), ast_config_engine_deregister(), ast_db_freetree(), ast_db_gettree(), config_odbc(), config_pgsql(), do_monitor(), gtalk_free_candidates(), internal_ao2_callback(), jingle_free_candidates(), load_password(), node_lookup(), npval2(), try_firmware(), and update_last().

ast_mutex_t lock

Definition at line 930 of file app_meetme.c.

Referenced by append_lock_information(), ast_localtime_wakeup_monitor(), load_rpt_vars(), reload(), rpt_master(), smdi_message_wait(), unload_module(), and write_cdr().

struct ast_data_handler meetme_data_provider [static]

Initial value:

Definition at line 7007 of file app_meetme.c.

struct ast_data_entry meetme_data_providers[] [static]

Initial value:

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

Definition at line 7012 of file app_meetme.c.

Referenced by load_module().

struct ast_custom_function meetme_info_acf [static]

Initial value:

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

Definition at line 6878 of file app_meetme.c.

Referenced by load_module(), and unload_module().

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 = ((uint64_t)1 << 32) , .arg_index = OPT_ARG_INTROMSG + 1 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, } [static]

Definition at line 653 of file app_meetme.c.

Referenced by conf_exec().

static int reload

A reload has been requested

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

int rt_schedule [static]

Definition at line 663 of file app_meetme.c.

struct { ... } sla [static]

A structure for data used by the sla thread.

Referenced by dial_trunk(), load_config(), queue_ringing_trunk(), sla_calc_station_timeouts(), sla_calc_trunk_timeouts(), sla_check_failed_station(), sla_check_reload(), sla_check_ringing_station(), sla_choose_ringing_trunk(), sla_destroy(), sla_handle_dial_state_event(), sla_handle_ringing_trunk_event(), sla_hangup_stations(), sla_load_config(), sla_queue_event_full(), sla_ring_station(), sla_ring_stations(), sla_station_exec(), sla_stop_ringing_station(), sla_thread(), and sla_trunk_exec().

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

Definition at line 870 of file app_meetme.c.

Referenced by destroy_station(), destroy_trunk(), and sla_destroy().

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

Definition at line 6282 of file app_meetme.c.

Referenced by sla_trunk_exec().

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

Definition at line 659 of file app_meetme.c.

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

Definition at line 660 of file app_meetme.c.

unsigned int stop

Definition at line 935 of file app_meetme.c.

Referenced by controlplayback_exec(), cops_gate_cmd(), handle_controlstreamfile(), pktccops_show_pools(), and queue_exec().

pthread_t thread

The SLA thread ID

Definition at line 928 of file app_meetme.c.

Referenced by __schedule_action(), ast_bridge_depart(), bridge_call_thread_launch(), cleanup_thread_list(), find_idle_thread(), handle_cli_iax2_show_threads(), handle_deferred_full_frames(), iax2_process_thread(), iax2_process_thread_cleanup(), insert_idle_thread(), launch_monitor_thread(), load_module(), multiplexed_add_or_remove(), socket_process(), socket_read(), start_network_thread(), and unload_module().


Generated on Mon Jun 27 16:50:58 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7