Wed Apr 6 11:29:49 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 6883 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 6900 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 6256 of file app_meetme.c.

06256      {
06257    SLA_TRUNK_OPT_MOH = (1 << 0),
06258 };

anonymous enum

Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 6260 of file app_meetme.c.

06260      {
06261    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
06262    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
06263 };

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

static void __unreg_module ( void   )  [static]

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

06813 {
06814    struct ast_conference *conf;
06815    char *parse;
06816    int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
06817    AST_DECLARE_APP_ARGS(args,
06818       AST_APP_ARG(keyword);
06819       AST_APP_ARG(confno);
06820    );
06821 
06822    if (ast_strlen_zero(data)) {
06823       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
06824       return -1;
06825    }
06826 
06827    parse = ast_strdupa(data);
06828    AST_STANDARD_APP_ARGS(args, parse);
06829 
06830    if (ast_strlen_zero(args.keyword)) {
06831       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
06832       return -1;
06833    }
06834 
06835    if (ast_strlen_zero(args.confno)) {
06836       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
06837       return -1;
06838    }
06839 
06840    AST_LIST_LOCK(&confs);
06841    AST_LIST_TRAVERSE(&confs, conf, list) {
06842       if (!strcmp(args.confno, conf->confno)) {
06843          result = acf_meetme_info_eval(args.keyword, conf);
06844          break;
06845       }
06846    }
06847    AST_LIST_UNLOCK(&confs);
06848 
06849    if (result > -1) {
06850       snprintf(buf, len, "%d", result);
06851    } else if (result == -1) {
06852       ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
06853       snprintf(buf, len, "0");
06854    } else if (result == -2) {
06855       ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno); 
06856       snprintf(buf, len, "0");
06857    }
06858 
06859    return 0;
06860 }

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

Definition at line 6794 of file app_meetme.c.

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

Referenced by acf_meetme_info().

06795 {
06796    if (!strcasecmp("lock", keyword)) {
06797       return conf->locked;
06798    } else if (!strcasecmp("parties", keyword)) {
06799       return conf->users;
06800    } else if (!strcasecmp("activity", keyword)) {
06801       time_t now;
06802       now = time(NULL);
06803       return (now - conf->start);
06804    } else if (!strcasecmp("dynamic", keyword)) {
06805       return conf->isdynamic;
06806    } else {
06807       return -1;
06808    }
06809 
06810 }

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

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

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

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

Definition at line 4727 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04728 {
04729    return meetmemute(s, m, 1);
04730 }

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

Definition at line 4732 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04733 {
04734    return meetmemute(s, m, 0);
04735 }

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

The MeetMeadmin application.

MeetMeAdmin(confno, command, caller)

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

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

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

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

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

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

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

05117 {
05118    ast_answer(chan);
05119    ast_indicate(chan, -1);
05120 }

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, 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_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          ast_free(cnf);
01224          cnf = NULL;
01225          goto cnfout;
01226       }
01227    }
01228 
01229    cnf->dahdiconf = dahdic.confno;
01230 
01231    /* Setup a new channel for playback of audio files */
01232    cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, chan, "pseudo", NULL);
01233    if (cnf->chan) {
01234       ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
01235       ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
01236       dahdic.chan = 0;
01237       dahdic.confno = cnf->dahdiconf;
01238       dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01239       if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
01240          if (test) {
01241             ast_test_status_update(test, "Error setting conference on pseudo channel\n");
01242          }
01243          ast_log(LOG_WARNING, "Error setting conference\n");
01244          if (cnf->chan)
01245             ast_hangup(cnf->chan);
01246          else
01247             close(cnf->fd);
01248 
01249          ast_free(cnf);
01250          cnf = NULL;
01251          goto cnfout;
01252       }
01253    }
01254 
01255    /* Fill the conference struct */
01256    cnf->start = time(NULL);
01257    cnf->maxusers = 0x7fffffff;
01258    cnf->isdynamic = dynamic ? 1 : 0;
01259    ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
01260    AST_LIST_INSERT_HEAD(&confs, cnf, list);
01261 
01262    /* Reserve conference number in map */
01263    if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01264       conf_map[confno_int] = 1;
01265    
01266 cnfout:
01267    if (cnf)
01268       ast_atomic_fetchadd_int(&cnf->refcount, refcount);
01269 
01270    AST_LIST_UNLOCK(&confs);
01271 
01272    return cnf;
01273 }

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

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

02109 {
02110    if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02111       return 1;
02112    }
02113 
02114    return (chan->_state == AST_STATE_UP);
02115 }

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

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

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

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

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

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

The meetme() application.

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

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

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

Definition at line 1754 of file app_meetme.c.

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

Referenced by conf_run().

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

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

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

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

01855 {
01856    struct ast_conf_user *user;
01857    struct ao2_iterator user_iter;
01858 
01859    user_iter = ao2_iterator_init(conf->usercontainer, 0);
01860    while ((user = ao2_iterator_next(&user_iter))) {
01861       if (user == sender) {
01862          ao2_ref(user, -1);
01863          continue;
01864       }
01865       if (ast_write(user->chan, f) < 0)
01866          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01867       ao2_ref(user, -1);
01868    }
01869    ao2_iterator_destroy(&user_iter);
01870 }

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

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

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

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

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

02026 {
02027    char *original_moh;
02028 
02029    ast_channel_lock(chan);
02030    original_moh = ast_strdupa(chan->musicclass);
02031    ast_string_field_set(chan, musicclass, musicclass);
02032    ast_channel_unlock(chan);
02033 
02034    ast_moh_start(chan, original_moh, NULL);
02035 
02036    ast_channel_lock(chan);
02037    ast_string_field_set(chan, musicclass, original_moh);
02038    ast_channel_unlock(chan);
02039 }

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

The MeetmeCount application.

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

04049 {
04050    int res = 0;
04051    struct ast_conference *conf;
04052    int count;
04053    char *localdata;
04054    char val[80] = "0"; 
04055    AST_DECLARE_APP_ARGS(args,
04056       AST_APP_ARG(confno);
04057       AST_APP_ARG(varname);
04058    );
04059 
04060    if (ast_strlen_zero(data)) {
04061       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
04062       return -1;
04063    }
04064    
04065    if (!(localdata = ast_strdupa(data)))
04066       return -1;
04067 
04068    AST_STANDARD_APP_ARGS(args, localdata);
04069    
04070    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
04071 
04072    if (conf) {
04073       count = conf->users;
04074       dispose_conf(conf);
04075       conf = NULL;
04076    } else
04077       count = 0;
04078 
04079    if (!ast_strlen_zero(args.varname)) {
04080       /* have var so load it and exit */
04081       snprintf(val, sizeof(val), "%d", count);
04082       pbx_builtin_setvar_helper(chan, args.varname, val);
04083    } else {
04084       if (chan->_state != AST_STATE_UP) {
04085          ast_answer(chan);
04086       }
04087       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
04088    }
04089 
04090    return res;
04091 }

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

Definition at line 6223 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

06224 {
06225    struct sla_trunk_ref *trunk_ref;
06226 
06227    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
06228       return NULL;
06229 
06230    trunk_ref->trunk = trunk;
06231 
06232    return trunk_ref;
06233 }

static void destroy_station ( struct sla_station station  )  [static]

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

06434 {
06435    struct sla_trunk_ref *trunk_ref;
06436 
06437    if (!ast_strlen_zero(station->autocontext)) {
06438       AST_RWLIST_RDLOCK(&sla_trunks);
06439       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06440          char exten[AST_MAX_EXTENSION];
06441          char hint[AST_MAX_APP];
06442          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06443          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06444          ast_context_remove_extension(station->autocontext, exten, 
06445             1, sla_registrar);
06446          ast_context_remove_extension(station->autocontext, hint, 
06447             PRIORITY_HINT, sla_registrar);
06448       }
06449       AST_RWLIST_UNLOCK(&sla_trunks);
06450    }
06451 
06452    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
06453       ast_free(trunk_ref);
06454 
06455    ast_string_field_free_memory(station);
06456    ast_free(station);
06457 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

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

06420 {
06421    struct sla_station_ref *station_ref;
06422 
06423    if (!ast_strlen_zero(trunk->autocontext))
06424       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
06425 
06426    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
06427       ast_free(station_ref);
06428 
06429    ast_string_field_free_memory(trunk);
06430    ast_free(trunk);
06431 }

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

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

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

static int dispose_conf ( struct ast_conference conf  )  [static]

Decrement reference counts, as incremented by find_conf().

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

01945 {
01946    int res = 0;
01947    int confno_int = 0;
01948 
01949    AST_LIST_LOCK(&confs);
01950    if (ast_atomic_dec_and_test(&conf->refcount)) {
01951       /* Take the conference room number out of an inuse state */
01952       if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
01953          conf_map[confno_int] = 0;
01954       }
01955       conf_free(conf);
01956       res = 1;
01957    }
01958    AST_LIST_UNLOCK(&confs);
01959 
01960    return res;
01961 }

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

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

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

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

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

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

04402 {
04403    struct ast_conf_user *user = NULL;
04404    int cid;
04405    
04406    sscanf(callerident, "%30i", &cid);
04407    if (conf && callerident) {
04408       user = ao2_find(conf->usercontainer, &cid, 0);
04409       /* reference decremented later in admin_exec */
04410       return user;
04411    }
04412    return NULL;
04413 }

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

Definition at line 2041 of file app_meetme.c.

References CONF_HASJOIN.

Referenced by announce_thread().

02042 {
02043    switch (type) {
02044    case CONF_HASLEFT:
02045       return "conf-hasleft";
02046       break;
02047    case CONF_HASJOIN:
02048       return "conf-hasjoin";
02049       break;
02050    default:
02051       return "";
02052    }
02053 }

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

06870 {
06871    load_config_meetme();
06872 
06873    if (reload && sla.thread != AST_PTHREADT_NULL) {
06874       sla_queue_event(SLA_EVENT_RELOAD);
06875       ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
06876          "and will be completed when the system is idle.\n");
06877       return 0;
06878    }
06879    
06880    return sla_load_config(0);
06881 }

static void load_config_meetme ( void   )  [static]

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

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

static int load_module ( void   )  [static]

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

07095 {
07096    int res = 0;
07097 
07098    res |= load_config(0);
07099 
07100    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07101    res |= ast_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute);
07102    res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute);
07103    res |= ast_manager_register_xml("MeetmeList", EVENT_FLAG_REPORTING, action_meetmelist);
07104    res |= ast_register_application_xml(app4, channel_admin_exec);
07105    res |= ast_register_application_xml(app3, admin_exec);
07106    res |= ast_register_application_xml(app2, count_exec);
07107    res |= ast_register_application_xml(app, conf_exec);
07108    res |= ast_register_application_xml(slastation_app, sla_station_exec);
07109    res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
07110 
07111 #ifdef TEST_FRAMEWORK
07112    AST_TEST_REGISTER(test_meetme_data_provider);
07113 #endif
07114    ast_data_register_multiple(meetme_data_providers, ARRAY_LEN(meetme_data_providers));
07115 
07116    res |= ast_devstate_prov_add("Meetme", meetmestate);
07117    res |= ast_devstate_prov_add("SLA", sla_state);
07118 
07119    res |= ast_custom_function_register(&meetme_info_acf);
07120    ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
07121 
07122    return res;
07123 }

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

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

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

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

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

06960 {
06961    struct ast_conference *cnf;
06962    struct ast_data *data_meetme, *data_meetme_users;
06963 
06964    AST_LIST_LOCK(&confs);
06965    AST_LIST_TRAVERSE(&confs, cnf, list) {
06966       data_meetme = ast_data_add_node(data_root, "meetme");
06967       if (!data_meetme) {
06968          continue;
06969       }
06970 
06971       ast_data_add_structure(ast_conference, data_meetme, cnf);
06972 
06973       if (ao2_container_count(cnf->usercontainer)) {
06974          data_meetme_users = ast_data_add_node(data_meetme, "users");
06975          if (!data_meetme_users) {
06976             ast_data_remove_node(data_root, data_meetme);
06977             continue;
06978          }
06979 
06980          ao2_callback(cnf->usercontainer, OBJ_NODATA, user_add_provider_cb, data_meetme_users); 
06981       }
06982 
06983       if (!ast_data_search_match(search, data_meetme)) {
06984          ast_data_remove_node(data_root, data_meetme);
06985       }
06986    }
06987    AST_LIST_UNLOCK(&confs);
06988 
06989    return 0;
06990 }

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

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

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

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

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

04668 {
04669    struct ast_conference *conf;
04670    struct ast_conf_user *user;
04671    const char *confid = astman_get_header(m, "Meetme");
04672    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
04673    int userno;
04674 
04675    if (ast_strlen_zero(confid)) {
04676       astman_send_error(s, m, "Meetme conference not specified");
04677       return 0;
04678    }
04679 
04680    if (ast_strlen_zero(userid)) {
04681       astman_send_error(s, m, "Meetme user number not specified");
04682       return 0;
04683    }
04684 
04685    userno = strtoul(userid, &userid, 10);
04686 
04687    if (*userid) {
04688       astman_send_error(s, m, "Invalid user number");
04689       return 0;
04690    }
04691 
04692    /* Look in the conference list */
04693    AST_LIST_LOCK(&confs);
04694    AST_LIST_TRAVERSE(&confs, conf, list) {
04695       if (!strcmp(confid, conf->confno))
04696          break;
04697    }
04698 
04699    if (!conf) {
04700       AST_LIST_UNLOCK(&confs);
04701       astman_send_error(s, m, "Meetme conference does not exist");
04702       return 0;
04703    }
04704 
04705    user = ao2_find(conf->usercontainer, &userno, 0);
04706 
04707    if (!user) {
04708       AST_LIST_UNLOCK(&confs);
04709       astman_send_error(s, m, "User number not found");
04710       return 0;
04711    }
04712 
04713    if (mute)
04714       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
04715    else
04716       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
04717 
04718    AST_LIST_UNLOCK(&confs);
04719 
04720    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);
04721 
04722    ao2_ref(user, -1);
04723    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
04724    return 0;
04725 }

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

Callback for devicestate providers.

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

04874 {
04875    struct ast_conference *conf;
04876 
04877    /* Find conference */
04878    AST_LIST_LOCK(&confs);
04879    AST_LIST_TRAVERSE(&confs, conf, list) {
04880       if (!strcmp(data, conf->confno))
04881          break;
04882    }
04883    AST_LIST_UNLOCK(&confs);
04884    if (!conf)
04885       return AST_DEVICE_INVALID;
04886 
04887 
04888    /* SKREP to fill */
04889    if (!conf->users)
04890       return AST_DEVICE_NOT_INUSE;
04891 
04892    return AST_DEVICE_INUSE;
04893 }

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

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

06236 {
06237    struct sla_ringing_trunk *ringing_trunk;
06238 
06239    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
06240       return NULL;
06241    
06242    ringing_trunk->trunk = trunk;
06243    ringing_trunk->ring_begin = ast_tvnow();
06244 
06245    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
06246 
06247    ast_mutex_lock(&sla.lock);
06248    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
06249    ast_mutex_unlock(&sla.lock);
06250 
06251    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06252 
06253    return ringing_trunk;
06254 }

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

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

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

static int reload ( void   )  [static]

Definition at line 7125 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

07126 {
07127    ast_unload_realtime("meetme");
07128    return load_config(1);
07129 }

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

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

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

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

05123 {
05124    struct sla_station *station;
05125    struct sla_trunk_ref *trunk_ref;
05126    struct ast_str *conf_name = ast_str_create(16);
05127    struct ast_flags64 conf_flags = { 0 };
05128    struct ast_conference *conf;
05129 
05130    {
05131       struct run_station_args *args = data;
05132       station = args->station;
05133       trunk_ref = args->trunk_ref;
05134       ast_mutex_lock(args->cond_lock);
05135       ast_cond_signal(args->cond);
05136       ast_mutex_unlock(args->cond_lock);
05137       /* args is no longer valid here. */
05138    }
05139 
05140    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
05141    ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
05142    ast_set_flag64(&conf_flags, 
05143       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05144    answer_trunk_chan(trunk_ref->chan);
05145    conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan, NULL);
05146    if (conf) {
05147       conf_run(trunk_ref->chan, conf, &conf_flags, NULL);
05148       dispose_conf(conf);
05149       conf = NULL;
05150    }
05151    trunk_ref->chan = NULL;
05152    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05153       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05154       ast_str_append(&conf_name, 0, ",K");
05155       admin_exec(NULL, ast_str_buffer(conf_name));
05156       trunk_ref->trunk->hold_stations = 0;
05157       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05158    }
05159 
05160    ast_dial_join(station->dial);
05161    ast_dial_destroy(station->dial);
05162    station->dial = NULL;
05163    ast_free(conf_name);
05164 
05165    return NULL;
05166 }

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

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

02118 {
02119    ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking",
02120          "Channel: %s\r\n"
02121          "Uniqueid: %s\r\n"
02122          "Meetme: %s\r\n"
02123          "Usernum: %d\r\n"
02124          "Status: %s\r\n",
02125          chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
02126 }

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

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

Referenced by conf_run().

02129 {
02130    int last_talking = user->talking;
02131    if (last_talking == talking)
02132       return;
02133 
02134    user->talking = talking;
02135 
02136    if (monitor) {
02137       /* Check if talking state changed. Take care of -1 which means unmonitored */
02138       int was_talking = (last_talking > 0);
02139       int now_talking = (talking > 0);
02140       if (was_talking != now_talking) {
02141          send_talking_event(chan, conf, user, now_talking);
02142       }
02143    }
02144 }

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

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

06578 {
06579    struct sla_trunk *trunk;
06580    struct sla_trunk_ref *trunk_ref;
06581    struct sla_station_ref *station_ref;
06582    char *trunk_name, *options, *cur;
06583 
06584    options = ast_strdupa(var->value);
06585    trunk_name = strsep(&options, ",");
06586    
06587    AST_RWLIST_RDLOCK(&sla_trunks);
06588    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
06589       if (!strcasecmp(trunk->name, trunk_name))
06590          break;
06591    }
06592 
06593    AST_RWLIST_UNLOCK(&sla_trunks);
06594    if (!trunk) {
06595       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
06596       return;
06597    }
06598    if (!(trunk_ref = create_trunk_ref(trunk)))
06599       return;
06600    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
06601 
06602    while ((cur = strsep(&options, ","))) {
06603       char *name, *value = cur;
06604       name = strsep(&value, "=");
06605       if (!strcasecmp(name, "ringtimeout")) {
06606          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
06607             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
06608                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06609             trunk_ref->ring_timeout = 0;
06610          }
06611       } else if (!strcasecmp(name, "ringdelay")) {
06612          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
06613             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
06614                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06615             trunk_ref->ring_delay = 0;
06616          }
06617       } else {
06618          ast_log(LOG_WARNING, "Invalid option '%s' for "
06619             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
06620       }
06621    }
06622 
06623    if (!(station_ref = sla_create_station_ref(station))) {
06624       ast_free(trunk_ref);
06625       return;
06626    }
06627    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
06628    AST_RWLIST_WRLOCK(&sla_trunks);
06629    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
06630    AST_RWLIST_UNLOCK(&sla_trunks);
06631    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
06632 }

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

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

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

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

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

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

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

05735 {
05736    struct sla_station *station;
05737    int res = 0;
05738 
05739    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05740       struct sla_ringing_trunk *ringing_trunk;
05741       int time_left;
05742 
05743       /* Ignore stations already ringing */
05744       if (sla_check_ringing_station(station))
05745          continue;
05746 
05747       /* Ignore stations already on a call */
05748       if (sla_check_inuse_station(station))
05749          continue;
05750 
05751       /* Ignore stations that don't have one of their trunks ringing */
05752       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
05753          continue;
05754 
05755       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
05756          continue;
05757 
05758       /* If there is no time left, then the station needs to start ringing.
05759        * Return non-zero so that an event will be queued up an event to 
05760        * make that happen. */
05761       if (time_left <= 0) {
05762          res = 1;
05763          continue;
05764       }
05765 
05766       if (time_left < *timeout)
05767          *timeout = time_left;
05768    }
05769 
05770    return res;
05771 }

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

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

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

05622 {
05623    struct sla_ringing_trunk *ringing_trunk;
05624    int res = 0;
05625 
05626    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05627       int time_left, time_elapsed;
05628       if (!ringing_trunk->trunk->ring_timeout)
05629          continue;
05630       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05631       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
05632       if (time_left <= 0) {
05633          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
05634          AST_LIST_REMOVE_CURRENT(entry);
05635          sla_stop_ringing_trunk(ringing_trunk);
05636          res = 1;
05637          continue;
05638       }
05639       if (time_left < *timeout)
05640          *timeout = time_left;
05641    }
05642    AST_LIST_TRAVERSE_SAFE_END;
05643 
05644    return res;
05645 }

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

05092 {
05093    struct sla_station *station;
05094    struct sla_trunk_ref *trunk_ref;
05095 
05096    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05097       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05098          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
05099             || trunk_ref == exclude)
05100             continue;
05101          trunk_ref->state = state;
05102          ast_devstate_changed(sla_state_to_devstate(state), 
05103             "SLA:%s_%s", station->name, trunk->name);
05104          break;
05105       }
05106    }
05107 }

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

Definition at line 6489 of file app_meetme.c.

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

Referenced by sla_build_trunk().

06490 {
06491    char *tech, *tech_data;
06492 
06493    tech_data = ast_strdupa(device);
06494    tech = strsep(&tech_data, "/");
06495 
06496    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
06497       return -1;
06498 
06499    return 0;
06500 }

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

05371 {
05372    struct sla_failed_station *failed_station;
05373    int res = 0;
05374 
05375    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
05376       if (station != failed_station->station)
05377          continue;
05378       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
05379          AST_LIST_REMOVE_CURRENT(entry);
05380          ast_free(failed_station);
05381          break;
05382       }
05383       res = 1;
05384    }
05385    AST_LIST_TRAVERSE_SAFE_END
05386 
05387    return res;
05388 }

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

Check to see if a station is in use.

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

05456 {
05457    struct sla_trunk_ref *trunk_ref;
05458 
05459    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05460       if (trunk_ref->chan)
05461          return 1;
05462    }
05463 
05464    return 0;
05465 }

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

05814 {
05815    struct sla_station *station;
05816    struct sla_trunk *trunk;
05817 
05818    ast_mutex_lock(&sla.lock);
05819 
05820    if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
05821       || !AST_LIST_EMPTY(&sla.ringing_stations)) {
05822       ast_mutex_unlock(&sla.lock);
05823       return;
05824    }
05825 
05826    AST_RWLIST_RDLOCK(&sla_stations);
05827    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
05828       if (station->ref_count)
05829          break;
05830    }
05831    AST_RWLIST_UNLOCK(&sla_stations);
05832    if (station) {
05833       ast_mutex_unlock(&sla.lock);
05834       return;
05835    }
05836 
05837    AST_RWLIST_RDLOCK(&sla_trunks);
05838    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05839       if (trunk->ref_count)
05840          break;
05841    }
05842    AST_RWLIST_UNLOCK(&sla_trunks);
05843    if (trunk) {
05844       ast_mutex_unlock(&sla.lock);
05845       return;
05846    }
05847 
05848    /* We need to actually delete the previous versions of trunks and stations now */
05849    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_stations, station, entry) {
05850       AST_RWLIST_REMOVE_CURRENT(entry);
05851       ast_free(station);
05852    }
05853    AST_RWLIST_TRAVERSE_SAFE_END;
05854 
05855    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_trunks, trunk, entry) {
05856       AST_RWLIST_REMOVE_CURRENT(entry);
05857       ast_free(trunk);
05858    }
05859    AST_RWLIST_TRAVERSE_SAFE_END;
05860 
05861    /* yay */
05862    sla_load_config(1);
05863    sla.reload = 0;
05864 
05865    ast_mutex_unlock(&sla.lock);
05866 }

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

05356 {
05357    struct sla_ringing_station *ringing_station;
05358 
05359    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
05360       if (station == ringing_station->station)
05361          return 1;
05362    }
05363 
05364    return 0;
05365 }

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

05487 {
05488    struct sla_trunk_ref *trunk_ref;
05489    unsigned int delay = UINT_MAX;
05490    int time_left, time_elapsed;
05491 
05492    if (!ringing_trunk)
05493       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
05494    else
05495       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
05496 
05497    if (!ringing_trunk || !trunk_ref)
05498       return delay;
05499 
05500    /* If this station has a ring delay specific to the highest priority
05501     * ringing trunk, use that.  Otherwise, use the ring delay specified
05502     * globally for the station. */
05503    delay = trunk_ref->ring_delay;
05504    if (!delay)
05505       delay = station->ring_delay;
05506    if (!delay)
05507       return INT_MAX;
05508 
05509    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05510    time_left = (delay * 1000) - time_elapsed;
05511 
05512    return time_left;
05513 }

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

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

04997 {
04998    struct sla_station_ref *station_ref;
04999    struct sla_trunk_ref *trunk_ref;
05000 
05001    /* For each station that has this call on hold, check for private hold. */
05002    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
05003       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
05004          if (trunk_ref->trunk != trunk || station_ref->station == station)
05005             continue;
05006          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
05007             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
05008             return 1;
05009          return 0;
05010       }
05011    }
05012 
05013    return 0;
05014 }

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

05228 {
05229    struct sla_station_ref *timed_out_station;
05230 
05231    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
05232       if (station == timed_out_station->station)
05233          return 1;
05234    }
05235 
05236    return 0;
05237 }

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

06051 {
06052    struct sla_trunk_ref *trunk_ref = NULL;
06053 
06054    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06055       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
06056          break;
06057    }
06058 
06059    return trunk_ref;
06060 }

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

05249 {
05250    struct sla_trunk_ref *s_trunk_ref;
05251    struct sla_ringing_trunk *ringing_trunk = NULL;
05252 
05253    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
05254       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05255          /* Make sure this is the trunk we're looking for */
05256          if (s_trunk_ref->trunk != ringing_trunk->trunk)
05257             continue;
05258 
05259          /* This trunk on the station is ringing.  But, make sure this station
05260           * didn't already time out while this trunk was ringing. */
05261          if (sla_check_timed_out_station(ringing_trunk, station))
05262             continue;
05263 
05264          if (rm)
05265             AST_LIST_REMOVE_CURRENT(entry);
05266 
05267          if (trunk_ref)
05268             *trunk_ref = s_trunk_ref;
05269 
05270          break;
05271       }
05272       AST_LIST_TRAVERSE_SAFE_END;
05273    
05274       if (ringing_trunk)
05275          break;
05276    }
05277 
05278    return ringing_trunk;
05279 }

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

Definition at line 5060 of file app_meetme.c.

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

Referenced by sla_ring_station().

05061 {
05062    struct sla_ringing_station *ringing_station;
05063 
05064    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
05065       return NULL;
05066 
05067    ringing_station->station = station;
05068    ringing_station->ring_begin = ast_tvnow();
05069 
05070    return ringing_station;
05071 }

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

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

05049 {
05050    struct sla_station_ref *station_ref;
05051 
05052    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
05053       return NULL;
05054 
05055    station_ref->station = station;
05056 
05057    return station_ref;
05058 }

static void sla_destroy ( void   )  [static]

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

06460 {
06461    struct sla_trunk *trunk;
06462    struct sla_station *station;
06463 
06464    AST_RWLIST_WRLOCK(&sla_trunks);
06465    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
06466       destroy_trunk(trunk);
06467    AST_RWLIST_UNLOCK(&sla_trunks);
06468 
06469    AST_RWLIST_WRLOCK(&sla_stations);
06470    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
06471       destroy_station(station);
06472    AST_RWLIST_UNLOCK(&sla_stations);
06473 
06474    if (sla.thread != AST_PTHREADT_NULL) {
06475       ast_mutex_lock(&sla.lock);
06476       sla.stop = 1;
06477       ast_cond_signal(&sla.cond);
06478       ast_mutex_unlock(&sla.lock);
06479       pthread_join(sla.thread, NULL);
06480    }
06481 
06482    /* Drop any created contexts from the dialplan */
06483    ast_context_destroy(NULL, sla_registrar);
06484 
06485    ast_mutex_destroy(&sla.lock);
06486    ast_cond_destroy(&sla.cond);
06487 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 5218 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

05219 {
05220    sla_queue_event(SLA_EVENT_DIAL_STATE);
05221 }

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

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

Referenced by sla_station_exec().

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

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

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

Referenced by sla_trunk_exec().

04969 {
04970    struct sla_trunk *trunk = NULL;
04971 
04972    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04973       if (!strcasecmp(trunk->name, name))
04974          break;
04975    }
04976 
04977    return trunk;
04978 }

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

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

05469 {
05470    struct sla_trunk_ref *trunk_ref = NULL;
05471 
05472    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05473       if (trunk_ref->trunk == trunk)
05474          break;
05475    }
05476 
05477    return trunk_ref;
05478 }

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

05025 {
05026    struct sla_trunk_ref *trunk_ref = NULL;
05027 
05028    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05029       if (strcasecmp(trunk_ref->trunk->name, name))
05030          continue;
05031 
05032       if ( (trunk_ref->trunk->barge_disabled 
05033          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
05034          (trunk_ref->trunk->hold_stations 
05035          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
05036          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
05037          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
05038       {
05039          trunk_ref = NULL;
05040       }
05041 
05042       break;
05043    }
05044 
05045    return trunk_ref;
05046 }

static void sla_handle_dial_state_event ( void   )  [static]

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

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

static void sla_handle_hold_event ( struct sla_event event  )  [static]

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

05598 {
05599    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
05600    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
05601    ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
05602       event->station->name, event->trunk_ref->trunk->name);
05603    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
05604       INACTIVE_TRUNK_REFS, event->trunk_ref);
05605 
05606    if (event->trunk_ref->trunk->active_stations == 1) {
05607       /* The station putting it on hold is the only one on the call, so start
05608        * Music on hold to the trunk. */
05609       event->trunk_ref->trunk->on_hold = 1;
05610       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
05611    }
05612 
05613    ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
05614    event->trunk_ref->chan = NULL;
05615 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 5587 of file app_meetme.c.

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

Referenced by sla_thread().

05588 {
05589    ast_mutex_lock(&sla.lock);
05590    sla_ring_stations();
05591    ast_mutex_unlock(&sla.lock);
05592 
05593    /* Find stations that shouldn't be ringing anymore. */
05594    sla_hangup_stations();
05595 }

static void sla_hangup_stations ( void   )  [static]

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

05560 {
05561    struct sla_trunk_ref *trunk_ref;
05562    struct sla_ringing_station *ringing_station;
05563 
05564    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05565       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05566          struct sla_ringing_trunk *ringing_trunk;
05567          ast_mutex_lock(&sla.lock);
05568          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05569             if (trunk_ref->trunk == ringing_trunk->trunk)
05570                break;
05571          }
05572          ast_mutex_unlock(&sla.lock);
05573          if (ringing_trunk)
05574             break;
05575       }
05576       if (!trunk_ref) {
05577          AST_LIST_REMOVE_CURRENT(entry);
05578          ast_dial_join(ringing_station->station->dial);
05579          ast_dial_destroy(ringing_station->station->dial);
05580          ringing_station->station->dial = NULL;
05581          ast_free(ringing_station);
05582       }
05583    }
05584    AST_LIST_TRAVERSE_SAFE_END
05585 }

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

Definition at line 1589 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01590 {
01591    const char *hold = "Unknown";
01592 
01593    switch (hold_access) {
01594    case SLA_HOLD_OPEN:
01595       hold = "Open";
01596       break;
01597    case SLA_HOLD_PRIVATE:
01598       hold = "Private";
01599    default:
01600       break;
01601    }
01602 
01603    return hold;
01604 }

static int sla_load_config ( int  reload  )  [static]

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

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

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

05776 {
05777    unsigned int timeout = UINT_MAX;
05778    struct timeval wait;
05779    unsigned int change_made = 0;
05780 
05781    /* Check for ring timeouts on ringing trunks */
05782    if (sla_calc_trunk_timeouts(&timeout))
05783       change_made = 1;
05784 
05785    /* Check for ring timeouts on ringing stations */
05786    if (sla_calc_station_timeouts(&timeout))
05787       change_made = 1;
05788 
05789    /* Check for station ring delays */
05790    if (sla_calc_station_delays(&timeout))
05791       change_made = 1;
05792 
05793    /* queue reprocessing of ringing trunks */
05794    if (change_made)
05795       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
05796 
05797    /* No timeout */
05798    if (timeout == UINT_MAX)
05799       return 0;
05800 
05801    if (ts) {
05802       wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
05803       ts->tv_sec = wait.tv_sec;
05804       ts->tv_nsec = wait.tv_usec * 1000;
05805    }
05806 
05807    return 1;
05808 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

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

01905 {
01906    sla_queue_event_full(type, NULL, NULL, 1);
01907 }

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

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

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

01874 {
01875    struct sla_event *event;
01876 
01877    if (sla.thread == AST_PTHREADT_NULL) {
01878       return;
01879    }
01880 
01881    if (!(event = ast_calloc(1, sizeof(*event))))
01882       return;
01883 
01884    event->type = type;
01885    event->trunk_ref = trunk_ref;
01886    event->station = station;
01887 
01888    if (!lock) {
01889       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01890       return;
01891    }
01892 
01893    ast_mutex_lock(&sla.lock);
01894    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01895    ast_cond_signal(&sla.cond);
01896    ast_mutex_unlock(&sla.lock);
01897 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1899 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01900 {
01901    sla_queue_event_full(type, NULL, NULL, 0);
01902 }

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

05394 {
05395    char *tech, *tech_data;
05396    struct ast_dial *dial;
05397    struct sla_ringing_station *ringing_station;
05398    enum ast_dial_result res;
05399    int caller_is_saved;
05400    struct ast_party_caller caller;
05401 
05402    if (!(dial = ast_dial_create()))
05403       return -1;
05404 
05405    ast_dial_set_state_callback(dial, sla_dial_state_callback);
05406    tech_data = ast_strdupa(station->device);
05407    tech = strsep(&tech_data, "/");
05408 
05409    if (ast_dial_append(dial, tech, tech_data) == -1) {
05410       ast_dial_destroy(dial);
05411       return -1;
05412    }
05413 
05414    /* Do we need to save off the caller ID data? */
05415    caller_is_saved = 0;
05416    if (!sla.attempt_callerid) {
05417       caller_is_saved = 1;
05418       caller = ringing_trunk->trunk->chan->caller;
05419       ast_party_caller_init(&ringing_trunk->trunk->chan->caller);
05420    }
05421 
05422    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
05423    
05424    /* Restore saved caller ID */
05425    if (caller_is_saved) {
05426       ast_party_caller_free(&ringing_trunk->trunk->chan->caller);
05427       ringing_trunk->trunk->chan->caller = caller;
05428    }
05429    
05430    if (res != AST_DIAL_RESULT_TRYING) {
05431       struct sla_failed_station *failed_station;
05432       ast_dial_destroy(dial);
05433       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
05434          return -1;
05435       failed_station->station = station;
05436       failed_station->last_try = ast_tvnow();
05437       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
05438       return -1;
05439    }
05440    if (!(ringing_station = sla_create_ringing_station(station))) {
05441       ast_dial_join(dial);
05442       ast_dial_destroy(dial);
05443       return -1;
05444    }
05445 
05446    station->dial = dial;
05447 
05448    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
05449 
05450    return 0;
05451 }

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

05519 {
05520    struct sla_station_ref *station_ref;
05521    struct sla_ringing_trunk *ringing_trunk;
05522 
05523    /* Make sure that every station that uses at least one of the ringing
05524     * trunks, is ringing. */
05525    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05526       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
05527          int time_left;
05528 
05529          /* Is this station already ringing? */
05530          if (sla_check_ringing_station(station_ref->station))
05531             continue;
05532 
05533          /* Is this station already in a call? */
05534          if (sla_check_inuse_station(station_ref->station))
05535             continue;
05536 
05537          /* Did we fail to dial this station earlier?  If so, has it been
05538           * a minute since we tried? */
05539          if (sla_check_failed_station(station_ref->station))
05540             continue;
05541 
05542          /* If this station already timed out while this trunk was ringing,
05543           * do not dial it again for this ringing trunk. */
05544          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
05545             continue;
05546 
05547          /* Check for a ring delay in progress */
05548          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
05549          if (time_left != INT_MAX && time_left > 0)
05550             continue;
05551 
05552          /* It is time to make this station begin to ring.  Do it! */
05553          sla_ring_station(ringing_trunk, station_ref->station);
05554       }
05555    }
05556    /* Now, all of the stations that should be ringing, are ringing. */
05557 }

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

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

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

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

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

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

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

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

06384 {
06385    char *buf, *station_name, *trunk_name;
06386    struct sla_station *station;
06387    struct sla_trunk_ref *trunk_ref;
06388    enum ast_device_state res = AST_DEVICE_INVALID;
06389 
06390    trunk_name = buf = ast_strdupa(data);
06391    station_name = strsep(&trunk_name, "_");
06392 
06393    AST_RWLIST_RDLOCK(&sla_stations);
06394    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
06395       if (strcasecmp(station_name, station->name))
06396          continue;
06397       AST_RWLIST_RDLOCK(&sla_trunks);
06398       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06399          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
06400             break;
06401       }
06402       if (!trunk_ref) {
06403          AST_RWLIST_UNLOCK(&sla_trunks);
06404          break;
06405       }
06406       res = sla_state_to_devstate(trunk_ref->state);
06407       AST_RWLIST_UNLOCK(&sla_trunks);
06408    }
06409    AST_RWLIST_UNLOCK(&sla_stations);
06410 
06411    if (res == AST_DEVICE_INVALID) {
06412       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
06413          trunk_name, station_name);
06414    }
06415 
06416    return res;
06417 }

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

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

05074 {
05075    switch (state) {
05076    case SLA_TRUNK_STATE_IDLE:
05077       return AST_DEVICE_NOT_INUSE;
05078    case SLA_TRUNK_STATE_RINGING:
05079       return AST_DEVICE_RINGING;
05080    case SLA_TRUNK_STATE_UP:
05081       return AST_DEVICE_INUSE;
05082    case SLA_TRUNK_STATE_ONHOLD:
05083    case SLA_TRUNK_STATE_ONHOLD_BYME:
05084       return AST_DEVICE_ONHOLD;
05085    }
05086 
05087    return AST_DEVICE_UNKNOWN;
05088 }

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

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

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

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

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

05185 {
05186    struct sla_ringing_trunk *ringing_trunk;
05187    struct sla_trunk_ref *trunk_ref;
05188    struct sla_station_ref *station_ref;
05189 
05190    ast_dial_join(ringing_station->station->dial);
05191    ast_dial_destroy(ringing_station->station->dial);
05192    ringing_station->station->dial = NULL;
05193 
05194    if (hangup == SLA_STATION_HANGUP_NORMAL)
05195       goto done;
05196 
05197    /* If the station is being hung up because of a timeout, then add it to the
05198     * list of timed out stations on each of the ringing trunks.  This is so
05199     * that when doing further processing to figure out which stations should be
05200     * ringing, which trunk to answer, determining timeouts, etc., we know which
05201     * ringing trunks we should ignore. */
05202    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05203       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05204          if (ringing_trunk->trunk == trunk_ref->trunk)
05205             break;
05206       }
05207       if (!trunk_ref)
05208          continue;
05209       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
05210          continue;
05211       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
05212    }
05213 
05214 done:
05215    ast_free(ringing_station);
05216 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

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

05169 {
05170    char buf[80];
05171    struct sla_station_ref *station_ref;
05172 
05173    snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
05174    admin_exec(NULL, buf);
05175    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05176 
05177    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
05178       ast_free(station_ref);
05179 
05180    ast_free(ringing_trunk);
05181 }

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

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

05869 {
05870    struct sla_failed_station *failed_station;
05871    struct sla_ringing_station *ringing_station;
05872 
05873    ast_mutex_lock(&sla.lock);
05874 
05875    while (!sla.stop) {
05876       struct sla_event *event;
05877       struct timespec ts = { 0, };
05878       unsigned int have_timeout = 0;
05879 
05880       if (AST_LIST_EMPTY(&sla.event_q)) {
05881          if ((have_timeout = sla_process_timers(&ts)))
05882             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
05883          else
05884             ast_cond_wait(&sla.cond, &sla.lock);
05885          if (sla.stop)
05886             break;
05887       }
05888 
05889       if (have_timeout)
05890          sla_process_timers(NULL);
05891 
05892       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
05893          ast_mutex_unlock(&sla.lock);
05894          switch (event->type) {
05895          case SLA_EVENT_HOLD:
05896             sla_handle_hold_event(event);
05897             break;
05898          case SLA_EVENT_DIAL_STATE:
05899             sla_handle_dial_state_event();
05900             break;
05901          case SLA_EVENT_RINGING_TRUNK:
05902             sla_handle_ringing_trunk_event();
05903             break;
05904          case SLA_EVENT_RELOAD:
05905             sla.reload = 1;
05906          case SLA_EVENT_CHECK_RELOAD:
05907             break;
05908          }
05909          ast_free(event);
05910          ast_mutex_lock(&sla.lock);
05911       }
05912 
05913       if (sla.reload) {
05914          sla_check_reload();
05915       }
05916    }
05917 
05918    ast_mutex_unlock(&sla.lock);
05919 
05920    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
05921       ast_free(ringing_station);
05922 
05923    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
05924       ast_free(failed_station);
05925 
05926    return NULL;
05927 }

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

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

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

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

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

01658 {
01659 #define S(e) case e: return # e;
01660    switch (state) {
01661    S(SLA_TRUNK_STATE_IDLE)
01662    S(SLA_TRUNK_STATE_RINGING)
01663    S(SLA_TRUNK_STATE_UP)
01664    S(SLA_TRUNK_STATE_ONHOLD)
01665    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01666    }
01667    return "Uknown State";
01668 #undef S
01669 }

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

07062 {
07063    int res = 0;
07064    
07065    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07066    res = ast_manager_unregister("MeetmeMute");
07067    res |= ast_manager_unregister("MeetmeUnmute");
07068    res |= ast_manager_unregister("MeetmeList");
07069    res |= ast_unregister_application(app4);
07070    res |= ast_unregister_application(app3);
07071    res |= ast_unregister_application(app2);
07072    res |= ast_unregister_application(app);
07073    res |= ast_unregister_application(slastation_app);
07074    res |= ast_unregister_application(slatrunk_app);
07075 
07076 #ifdef TEST_FRAMEWORK
07077    AST_TEST_UNREGISTER(test_meetme_data_provider);
07078 #endif
07079    ast_data_unregister(NULL);
07080 
07081    ast_devstate_prov_del("Meetme");
07082    ast_devstate_prov_del("SLA");
07083    
07084    sla_destroy();
07085    
07086    res |= ast_custom_function_unregister(&meetme_info_acf);
07087    ast_unload_realtime("meetme");
07088 
07089    return res;
07090 }

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

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

06913 {
06914    struct ast_data *data_meetme_user;
06915    struct ast_data *data_meetme_user_channel;
06916    struct ast_data *data_meetme_user_volume;
06917 
06918    struct ast_conf_user *user = obj;
06919    struct ast_data *data_meetme_users = arg;
06920 
06921    data_meetme_user = ast_data_add_node(data_meetme_users, "user");
06922    if (!data_meetme_user) {
06923       return 0;
06924    }
06925    /* user structure */
06926    ast_data_add_structure(ast_conf_user, data_meetme_user, user);
06927 
06928    /* user's channel */
06929    data_meetme_user_channel = ast_data_add_node(data_meetme_user, "channel");
06930    if (!data_meetme_user_channel) {
06931       return 0;
06932    }
06933 
06934    ast_channel_data_add_structure(data_meetme_user_channel, user->chan, 1);
06935 
06936    /* volume structure */
06937    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "listen-volume");
06938    if (!data_meetme_user_volume) {
06939       return 0;
06940    }
06941    ast_data_add_int(data_meetme_user_volume, "desired", user->listen.desired);
06942    ast_data_add_int(data_meetme_user_volume, "actual", user->listen.actual);
06943 
06944    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "talk-volume");
06945    if (!data_meetme_user_volume) {
06946       return 0;
06947    }
06948    ast_data_add_int(data_meetme_user_volume, "desired", user->talk.desired);
06949    ast_data_add_int(data_meetme_user_volume, "actual", user->talk.actual);
06950 
06951    return 0;
06952 }

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

Definition at line 4450 of file app_meetme.c.

References CMP_MATCH, CMP_STOP, and user.

Referenced by channel_admin_exec().

04451 {
04452    struct ast_conf_user *user = obj;
04453    const char *channel = args;
04454 
04455    if (!strcmp(user->chan->name, channel)) {
04456       return (CMP_MATCH | CMP_STOP);
04457    }
04458 
04459    return 0;
04460 }

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

Definition at line 4422 of file app_meetme.c.

References tweak_listen_volume(), and user.

Referenced by admin_exec().

04423 {
04424    struct ast_conf_user *user = obj;
04425    tweak_listen_volume(user, VOL_DOWN);
04426    return 0;
04427 }

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

Definition at line 4415 of file app_meetme.c.

References tweak_listen_volume(), user, and VOL_UP.

Referenced by admin_exec().

04416 {
04417    struct ast_conf_user *user = obj;
04418    tweak_listen_volume(user, VOL_UP);
04419    return 0;
04420 }

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

References reset_volumes(), and user.

Referenced by admin_exec().

04444 {
04445    struct ast_conf_user *user = obj;
04446    reset_volumes(user);
04447    return 0;
04448 }

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

Definition at line 2146 of file app_meetme.c.

References ADMINFLAG_KICKME, ast_test_flag64, CONFFLAG_ADMIN, and user.

Referenced by admin_exec(), and conf_run().

02147 {
02148    struct ast_conf_user *user = obj;
02149    /* actual pointer contents of check_admin_arg is irrelevant */
02150 
02151    if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
02152       user->adminflags |= ADMINFLAG_KICKME;
02153    }
02154    return 0;
02155 }

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

Definition at line 2168 of file app_meetme.c.

References ADMINFLAG_MUTED, ast_test_flag64, CONFFLAG_ADMIN, and user.

Referenced by admin_exec(), and conf_run().

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

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

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

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

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

Definition at line 4436 of file app_meetme.c.

References tweak_talk_volume(), and user.

Referenced by admin_exec().

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

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

Definition at line 4429 of file app_meetme.c.

References tweak_talk_volume(), user, and VOL_UP.

Referenced by admin_exec().

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


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 7136 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 7136 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 1747 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 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 6992 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 6997 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 6863 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 6267 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 Wed Apr 6 11:29:50 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7