Mon Oct 8 12:39:07 2012

Asterisk developer's documentation


app_meetme.c File Reference

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

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

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

enum  { ADMINFLAG_MUTED = (1 << 1), ADMINFLAG_SELFMUTED = (1 << 2), ADMINFLAG_KICKME = (1 << 3), ADMINFLAG_T_REQUEST = (1 << 4) }
enum  {
  CONFFLAG_ADMIN = (1 << 0), CONFFLAG_MONITOR = (1 << 1), CONFFLAG_KEYEXIT = (1 << 2), CONFFLAG_STARMENU = (1 << 3),
  CONFFLAG_TALKER = (1 << 4), CONFFLAG_QUIET = (1 << 5), CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6), CONFFLAG_AGI = (1 << 7),
  CONFFLAG_MOH = (1 << 8), CONFFLAG_MARKEDEXIT = (1 << 9), CONFFLAG_WAITMARKED = (1 << 10), CONFFLAG_EXIT_CONTEXT = (1 << 11),
  CONFFLAG_MARKEDUSER = (1 << 12), CONFFLAG_INTROUSER = (1 << 13), CONFFLAG_RECORDCONF = (1<< 14), CONFFLAG_MONITORTALKER = (1 << 15),
  CONFFLAG_DYNAMIC = (1 << 16), CONFFLAG_DYNAMICPIN = (1 << 17), CONFFLAG_EMPTY = (1 << 18), CONFFLAG_EMPTYNOPIN = (1 << 19),
  CONFFLAG_ALWAYSPROMPT = (1 << 20), CONFFLAG_OPTIMIZETALKER = (1 << 21), CONFFLAG_NOONLYPERSON = (1 << 22), CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
  CONFFLAG_STARTMUTED = (1 << 24), CONFFLAG_PASS_DTMF = (1 << 25), CONFFLAG_SLA_STATION = (1 << 26), CONFFLAG_SLA_TRUNK = (1 << 27),
  CONFFLAG_KICK_CONTINUE = (1 << 28), CONFFLAG_DURATION_STOP = (1 << 29), CONFFLAG_DURATION_LIMIT = (1 << 30)
}
enum  {
  OPT_ARG_WAITMARKED = 0, OPT_ARG_EXITKEYS = 1, OPT_ARG_DURATION_STOP = 2, OPT_ARG_DURATION_LIMIT = 3,
  OPT_ARG_MOH_CLASS = 4, OPT_ARG_INTROMSG = 5, OPT_ARG_ARRAY_SIZE = 6
}
enum  { SLA_TRUNK_OPT_MOH = (1 << 0) }
enum  { SLA_TRUNK_OPT_ARG_MOH_CLASS = 0, SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1 }
enum  announcetypes { CONF_HASJOIN, CONF_HASLEFT }
enum  entrance_sound { ENTER, LEAVE }
enum  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 void filename_parse (char *filename, char *buffer)
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags)
static struct ast_conferencefind_conf_realtime (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags, int *too_early, char **optargs)
static struct ast_conf_userfind_user (struct ast_conference *conf, const char *callerident)
static const char * get_announce_filename (enum announcetypes type)
static const char * istalking (int x)
static int load_config (int reload)
static void load_config_meetme (void)
static int load_module (void)
static char * meetme_cmd (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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, }
static const char *const app = "MeetMe"
static const char *const app2 = "MeetMeCount"
static const char *const app3 = "MeetMeAdmin"
static const char *const app4 = "MeetMeChannelAdmin"
static struct ast_module_infoast_module_info = &__mod_info
static int audio_buffers
 The number of audio buffers to be allocated on pseudo channels when in a conference.
static struct ast_cli_entry cli_meetme []
static unsigned int conf_map [1024] = {0, }
static int earlyalert
static int endalert
static int extendby
static int fuzzystart
static const char gain_map []
 Map 'volume' levels from -5 through +5 into decibel (dB) settings for channel drivers.
static struct ast_data_handler meetme_data_provider
static struct ast_data_entry meetme_data_providers []
static struct ast_custom_function meetme_info_acf
static struct ast_app_option meetme_opts [128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'G' ] = { .flag = (1ULL << 32) , .arg_index = OPT_ARG_INTROMSG + 1 }, [ '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 535 of file app_meetme.c.

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

#define CONF_SIZE   320

Definition at line 554 of file app_meetme.c.

#define CONFFLAG_INTROMSG   (1ULL << 32)

If set play an intro announcement at start of conference

Definition at line 618 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_NO_AUDIO_UNTIL_UP   (1ULL << 31)

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

Definition at line 616 of file app_meetme.c.

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

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 515 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 522 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 519 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

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

Referenced by conf_exec().

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

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

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 533 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 532 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_USER_DATA_EXPORT ( MEMBER   ) 

Definition at line 7002 of file app_meetme.c.

#define OPTIONS_LEN   100

Definition at line 682 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 516 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 524 of file app_meetme.c.

00524      {
00525    ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
00526    ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
00527    ADMINFLAG_KICKME =    (1 << 3),  /*!< User has been kicked */
00528    /*! User has requested to speak */
00529    ADMINFLAG_T_REQUEST = (1 << 4),
00530 };

anonymous enum

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

Definition at line 556 of file app_meetme.c.

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

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

00620      {
00621    OPT_ARG_WAITMARKED = 0,
00622    OPT_ARG_EXITKEYS   = 1,
00623    OPT_ARG_DURATION_STOP = 2,
00624    OPT_ARG_DURATION_LIMIT = 3,
00625    OPT_ARG_MOH_CLASS = 4,
00626    OPT_ARG_INTROMSG = 5,
00627    OPT_ARG_ARRAY_SIZE = 6,
00628 };

anonymous enum

Enumerator:
SLA_TRUNK_OPT_MOH 

Definition at line 6342 of file app_meetme.c.

06342      {
06343    SLA_TRUNK_OPT_MOH = (1 << 0),
06344 };

anonymous enum

Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 6346 of file app_meetme.c.

06346      {
06347    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
06348    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
06349 };

enum announcetypes

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 687 of file app_meetme.c.

00687                    {
00688    CONF_HASJOIN,
00689    CONF_HASLEFT
00690 };

enum entrance_sound

Enumerator:
ENTER 
LEAVE 

Definition at line 542 of file app_meetme.c.

00542                     {
00543    ENTER,
00544    LEAVE
00545 };

enum recording_state

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

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

00881                     {
00882    /*! A station has put the call on hold */
00883    SLA_EVENT_HOLD,
00884    /*! The state of a dial has changed */
00885    SLA_EVENT_DIAL_STATE,
00886    /*! The state of a ringing trunk has changed */
00887    SLA_EVENT_RINGING_TRUNK,
00888    /*! A reload of configuration has been requested */
00889    SLA_EVENT_RELOAD,
00890    /*! Poke the SLA thread so it can check if it can perform a reload */
00891    SLA_EVENT_CHECK_RELOAD,
00892 };

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

00791                      {
00792    /*! This means that any station can put it on hold, and any station
00793     * can retrieve the call from hold. */
00794    SLA_HOLD_OPEN,
00795    /*! This means that only the station that put the call on hold may
00796     * retrieve it from hold. */
00797    SLA_HOLD_PRIVATE,
00798 };

enum sla_station_hangup

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

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

enum sla_which_trunk_refs

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 778 of file app_meetme.c.

00778                           {
00779    ALL_TRUNK_REFS,
00780    INACTIVE_TRUNK_REFS,
00781 };

enum volume_action

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 537 of file app_meetme.c.

00537                    {
00538    VOL_UP,
00539    VOL_DOWN
00540 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 7238 of file app_meetme.c.

static void __unreg_module ( void   )  [static]

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

06915 {
06916    struct ast_conference *conf;
06917    char *parse;
06918    int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
06919    AST_DECLARE_APP_ARGS(args,
06920       AST_APP_ARG(keyword);
06921       AST_APP_ARG(confno);
06922    );
06923 
06924    if (ast_strlen_zero(data)) {
06925       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
06926       return -1;
06927    }
06928 
06929    parse = ast_strdupa(data);
06930    AST_STANDARD_APP_ARGS(args, parse);
06931 
06932    if (ast_strlen_zero(args.keyword)) {
06933       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
06934       return -1;
06935    }
06936 
06937    if (ast_strlen_zero(args.confno)) {
06938       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
06939       return -1;
06940    }
06941 
06942    AST_LIST_LOCK(&confs);
06943    AST_LIST_TRAVERSE(&confs, conf, list) {
06944       if (!strcmp(args.confno, conf->confno)) {
06945          result = acf_meetme_info_eval(args.keyword, conf);
06946          break;
06947       }
06948    }
06949    AST_LIST_UNLOCK(&confs);
06950 
06951    if (result > -1) {
06952       snprintf(buf, len, "%d", result);
06953    } else if (result == -1) {
06954       ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
06955       snprintf(buf, len, "0");
06956    } else if (result == -2) {
06957       ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno); 
06958       snprintf(buf, len, "0");
06959    }
06960 
06961    return 0;
06962 }

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

Definition at line 6896 of file app_meetme.c.

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

Referenced by acf_meetme_info().

06897 {
06898    if (!strcasecmp("lock", keyword)) {
06899       return conf->locked;
06900    } else if (!strcasecmp("parties", keyword)) {
06901       return conf->users;
06902    } else if (!strcasecmp("activity", keyword)) {
06903       time_t now;
06904       now = time(NULL);
06905       return (now - conf->start);
06906    } else if (!strcasecmp("dynamic", keyword)) {
06907       return conf->isdynamic;
06908    } else {
06909       return -1;
06910    }
06911 
06912 }

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

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

04804 {
04805    const char *actionid = astman_get_header(m, "ActionID");
04806    const char *conference = astman_get_header(m, "Conference");
04807    char idText[80] = "";
04808    struct ast_conference *cnf;
04809    struct ast_conf_user *user;
04810    struct ao2_iterator user_iter;
04811    int total = 0;
04812 
04813    if (!ast_strlen_zero(actionid))
04814       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04815 
04816    if (AST_LIST_EMPTY(&confs)) {
04817       astman_send_error(s, m, "No active conferences.");
04818       return 0;
04819    }
04820 
04821    astman_send_listack(s, m, "Meetme user list will follow", "start");
04822 
04823    /* Find the right conference */
04824    AST_LIST_LOCK(&confs);
04825    AST_LIST_TRAVERSE(&confs, cnf, list) {
04826       /* If we ask for one particular, and this isn't it, skip it */
04827       if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
04828          continue;
04829 
04830       /* Show all the users */
04831       user_iter = ao2_iterator_init(cnf->usercontainer, 0);
04832       while ((user = ao2_iterator_next(&user_iter))) {
04833          total++;
04834          astman_append(s,
04835             "Event: MeetmeList\r\n"
04836             "%s"
04837             "Conference: %s\r\n"
04838             "UserNumber: %d\r\n"
04839             "CallerIDNum: %s\r\n"
04840             "CallerIDName: %s\r\n"
04841             "ConnectedLineNum: %s\r\n"
04842             "ConnectedLineName: %s\r\n"
04843             "Channel: %s\r\n"
04844             "Admin: %s\r\n"
04845             "Role: %s\r\n"
04846             "MarkedUser: %s\r\n"
04847             "Muted: %s\r\n"
04848             "Talking: %s\r\n"
04849             "\r\n",
04850             idText,
04851             cnf->confno,
04852             user->user_no,
04853             S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
04854             S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
04855             S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
04856             S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<no name>"),
04857             user->chan->name,
04858             ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
04859             ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
04860             ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
04861             user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
04862             user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
04863          ao2_ref(user, -1);
04864       }
04865       ao2_iterator_destroy(&user_iter);
04866    }
04867    AST_LIST_UNLOCK(&confs);
04868    /* Send final confirmation */
04869    astman_append(s,
04870    "Event: MeetmeListComplete\r\n"
04871    "EventList: Complete\r\n"
04872    "ListItems: %d\r\n"
04873    "%s"
04874    "\r\n", total, idText);
04875    return 0;
04876 }

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

Definition at line 4793 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04794 {
04795    return meetmemute(s, m, 1);
04796 }

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

Definition at line 4798 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04799 {
04800    return meetmemute(s, m, 0);
04801 }

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

The MeetMeadmin application.

MeetMeAdmin(confno, command, caller)

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

04525                                                                   {
04526    char *params;
04527    struct ast_conference *cnf;
04528    struct ast_conf_user *user = NULL;
04529    AST_DECLARE_APP_ARGS(args,
04530       AST_APP_ARG(confno);
04531       AST_APP_ARG(command);
04532       AST_APP_ARG(user);
04533    );
04534    int res = 0;
04535 
04536    if (ast_strlen_zero(data)) {
04537       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
04538       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04539       return -1;
04540    }
04541 
04542    params = ast_strdupa(data);
04543    AST_STANDARD_APP_ARGS(args, params);
04544 
04545    if (!args.command) {
04546       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
04547       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04548       return -1;
04549    }
04550 
04551    AST_LIST_LOCK(&confs);
04552    AST_LIST_TRAVERSE(&confs, cnf, list) {
04553       if (!strcmp(cnf->confno, args.confno))
04554          break;
04555    }
04556 
04557    if (!cnf) {
04558       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
04559       AST_LIST_UNLOCK(&confs);
04560       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
04561       return 0;
04562    }
04563 
04564    ast_atomic_fetchadd_int(&cnf->refcount, 1);
04565 
04566    if (args.user) {
04567       user = find_user(cnf, args.user);
04568       if (!user) {
04569          ast_log(LOG_NOTICE, "Specified User not found!\n");
04570          res = -2;
04571          goto usernotfound;
04572       }
04573    }
04574 
04575    switch (*args.command) {
04576    case 76: /* L: Lock */ 
04577       cnf->locked = 1;
04578       break;
04579    case 108: /* l: Unlock */ 
04580       cnf->locked = 0;
04581       break;
04582    case 75: /* K: kick all users */
04583       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_kickme_cb, NULL);
04584       break;
04585    case 101: /* e: Eject last user*/
04586    {
04587       int max_no = 0;
04588 
04589       /* If they passed in a user, disregard it */
04590       if (user) {
04591          ao2_ref(user, -1);
04592       }
04593 
04594       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
04595       user = ao2_find(cnf->usercontainer, &max_no, 0);
04596       if (!ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))
04597          user->adminflags |= ADMINFLAG_KICKME;
04598       else {
04599          res = -1;
04600          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
04601       }
04602       ao2_ref(user, -1);
04603       break;
04604    }
04605    case 77: /* M: Mute */ 
04606       user->adminflags |= ADMINFLAG_MUTED;
04607       break;
04608    case 78: /* N: Mute all (non-admin) users */
04609       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_muted_cb, &cnf);
04610       break;               
04611    case 109: /* m: Unmute */ 
04612       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04613       break;
04614    case 110: /* n: Unmute all users */
04615       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, NULL);
04616       break;
04617    case 107: /* k: Kick user */ 
04618       user->adminflags |= ADMINFLAG_KICKME;
04619       break;
04620    case 118: /* v: Lower all users listen volume */
04621       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_voldown_cb, NULL);
04622       break;
04623    case 86: /* V: Raise all users listen volume */
04624       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_listen_volup_cb, NULL);
04625       break;
04626    case 115: /* s: Lower all users speaking volume */
04627       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_voldown_cb, NULL);
04628       break;
04629    case 83: /* S: Raise all users speaking volume */
04630       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_talk_volup_cb, NULL);
04631       break;
04632    case 82: /* R: Reset all volume levels */
04633       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_reset_vol_cb, NULL);
04634       break;
04635    case 114: /* r: Reset user's volume level */
04636       reset_volumes(user);
04637       break;
04638    case 85: /* U: Raise user's listen volume */
04639       tweak_listen_volume(user, VOL_UP);
04640       break;
04641    case 117: /* u: Lower user's listen volume */
04642       tweak_listen_volume(user, VOL_DOWN);
04643       break;
04644    case 84: /* T: Raise user's talk volume */
04645       tweak_talk_volume(user, VOL_UP);
04646       break;
04647    case 116: /* t: Lower user's talk volume */
04648       tweak_talk_volume(user, VOL_DOWN);
04649       break;
04650    case 'E': /* E: Extend conference */
04651       if (rt_extend_conf(args.confno)) {
04652          res = -1;
04653       }
04654       break;
04655    }
04656 
04657    if (args.user) {
04658       /* decrement reference from find_user */
04659       ao2_ref(user, -1);
04660    }
04661 usernotfound:
04662    AST_LIST_UNLOCK(&confs);
04663 
04664    dispose_conf(cnf);
04665    pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
04666 
04667    return 0;
04668 }

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

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

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

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

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

05216 {
05217    ast_answer(chan);
05218    ast_indicate(chan, -1);
05219 }

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

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

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

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

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

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

02127 {
02128    if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02129       return 1;
02130    }
02131 
02132    return (chan->_state == AST_STATE_UP);
02133 }

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

Definition at line 992 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

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

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

The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command).

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

04672                                                                           {
04673    char *params;
04674    struct ast_conference *conf = NULL;
04675    struct ast_conf_user *user = NULL;
04676    AST_DECLARE_APP_ARGS(args,
04677       AST_APP_ARG(channel);
04678       AST_APP_ARG(command);
04679    );
04680 
04681    if (ast_strlen_zero(data)) {
04682       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
04683       return -1;
04684    }
04685    
04686    params = ast_strdupa(data);
04687    AST_STANDARD_APP_ARGS(args, params);
04688 
04689    if (!args.channel) {
04690       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
04691       return -1;
04692    }
04693 
04694    if (!args.command) {
04695       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
04696       return -1;
04697    }
04698 
04699    AST_LIST_LOCK(&confs);
04700    AST_LIST_TRAVERSE(&confs, conf, list) {
04701       if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
04702          break;
04703       }
04704    }
04705    
04706    if (!user) {
04707       ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
04708       AST_LIST_UNLOCK(&confs);
04709       return 0;
04710    }
04711    
04712    /* perform the specified action */
04713    switch (*args.command) {
04714       case 77: /* M: Mute */ 
04715          user->adminflags |= ADMINFLAG_MUTED;
04716          break;
04717       case 109: /* m: Unmute */ 
04718          user->adminflags &= ~ADMINFLAG_MUTED;
04719          break;
04720       case 107: /* k: Kick user */ 
04721          user->adminflags |= ADMINFLAG_KICKME;
04722          break;
04723       default: /* unknown command */
04724          ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
04725          break;
04726    }
04727    ao2_ref(user, -1);
04728    AST_LIST_UNLOCK(&confs);
04729    
04730    return 0;
04731 }

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

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

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

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

The meetme() application.

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

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

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

Definition at line 1772 of file app_meetme.c.

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

Referenced by conf_run().

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

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

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

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

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

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

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

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

01873 {
01874    struct ast_conf_user *user;
01875    struct ao2_iterator user_iter;
01876 
01877    user_iter = ao2_iterator_init(conf->usercontainer, 0);
01878    while ((user = ao2_iterator_next(&user_iter))) {
01879       if (user == sender) {
01880          ao2_ref(user, -1);
01881          continue;
01882       }
01883       if (ast_write(user->chan, f) < 0)
01884          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01885       ao2_ref(user, -1);
01886    }
01887    ao2_iterator_destroy(&user_iter);
01888 }

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

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

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

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

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

02044 {
02045    char *original_moh;
02046 
02047    ast_channel_lock(chan);
02048    original_moh = ast_strdupa(chan->musicclass);
02049    ast_string_field_set(chan, musicclass, musicclass);
02050    ast_channel_unlock(chan);
02051 
02052    ast_moh_start(chan, original_moh, NULL);
02053 
02054    ast_channel_lock(chan);
02055    ast_string_field_set(chan, musicclass, original_moh);
02056    ast_channel_unlock(chan);
02057 }

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

The MeetmeCount application.

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

04097 {
04098    int res = 0;
04099    struct ast_conference *conf;
04100    int count;
04101    char *localdata;
04102    char val[80] = "0"; 
04103    AST_DECLARE_APP_ARGS(args,
04104       AST_APP_ARG(confno);
04105       AST_APP_ARG(varname);
04106    );
04107 
04108    if (ast_strlen_zero(data)) {
04109       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
04110       return -1;
04111    }
04112    
04113    if (!(localdata = ast_strdupa(data)))
04114       return -1;
04115 
04116    AST_STANDARD_APP_ARGS(args, localdata);
04117    
04118    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
04119 
04120    if (conf) {
04121       count = conf->users;
04122       dispose_conf(conf);
04123       conf = NULL;
04124    } else
04125       count = 0;
04126 
04127    if (!ast_strlen_zero(args.varname)) {
04128       /* have var so load it and exit */
04129       snprintf(val, sizeof(val), "%d", count);
04130       pbx_builtin_setvar_helper(chan, args.varname, val);
04131    } else {
04132       if (chan->_state != AST_STATE_UP) {
04133          ast_answer(chan);
04134       }
04135       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
04136    }
04137 
04138    return res;
04139 }

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

Definition at line 6309 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

06310 {
06311    struct sla_trunk_ref *trunk_ref;
06312 
06313    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
06314       return NULL;
06315 
06316    trunk_ref->trunk = trunk;
06317 
06318    return trunk_ref;
06319 }

static void destroy_station ( struct sla_station station  )  [static]

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

06518 {
06519    struct sla_trunk_ref *trunk_ref;
06520 
06521    if (!ast_strlen_zero(station->autocontext)) {
06522       AST_RWLIST_RDLOCK(&sla_trunks);
06523       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06524          char exten[AST_MAX_EXTENSION];
06525          char hint[AST_MAX_APP];
06526          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06527          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06528          ast_context_remove_extension(station->autocontext, exten, 
06529             1, sla_registrar);
06530          ast_context_remove_extension(station->autocontext, hint, 
06531             PRIORITY_HINT, sla_registrar);
06532       }
06533       AST_RWLIST_UNLOCK(&sla_trunks);
06534    }
06535 
06536    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
06537       ast_free(trunk_ref);
06538 
06539    ast_string_field_free_memory(station);
06540    ast_free(station);
06541 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

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

06504 {
06505    struct sla_station_ref *station_ref;
06506 
06507    if (!ast_strlen_zero(trunk->autocontext))
06508       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
06509 
06510    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
06511       ast_free(station_ref);
06512 
06513    ast_string_field_free_memory(trunk);
06514    ast_free(trunk);
06515 }

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

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

06023 {
06024    struct dial_trunk_args *args = data;
06025    struct ast_dial *dial;
06026    char *tech, *tech_data;
06027    enum ast_dial_result dial_res;
06028    char conf_name[MAX_CONFNUM];
06029    struct ast_conference *conf;
06030    struct ast_flags64 conf_flags = { 0 };
06031    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
06032    int caller_is_saved;
06033    struct ast_party_caller caller;
06034 
06035    if (!(dial = ast_dial_create())) {
06036       ast_mutex_lock(args->cond_lock);
06037       ast_cond_signal(args->cond);
06038       ast_mutex_unlock(args->cond_lock);
06039       return NULL;
06040    }
06041 
06042    tech_data = ast_strdupa(trunk_ref->trunk->device);
06043    tech = strsep(&tech_data, "/");
06044    if (ast_dial_append(dial, tech, tech_data) == -1) {
06045       ast_mutex_lock(args->cond_lock);
06046       ast_cond_signal(args->cond);
06047       ast_mutex_unlock(args->cond_lock);
06048       ast_dial_destroy(dial);
06049       return NULL;
06050    }
06051 
06052    /* Do we need to save of the caller ID data? */
06053    caller_is_saved = 0;
06054    if (!sla.attempt_callerid) {
06055       caller_is_saved = 1;
06056       caller = trunk_ref->chan->caller;
06057       ast_party_caller_init(&trunk_ref->chan->caller);
06058    }
06059 
06060    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
06061 
06062    /* Restore saved caller ID */
06063    if (caller_is_saved) {
06064       ast_party_caller_free(&trunk_ref->chan->caller);
06065       trunk_ref->chan->caller = caller;
06066    }
06067 
06068    if (dial_res != AST_DIAL_RESULT_TRYING) {
06069       ast_mutex_lock(args->cond_lock);
06070       ast_cond_signal(args->cond);
06071       ast_mutex_unlock(args->cond_lock);
06072       ast_dial_destroy(dial);
06073       return NULL;
06074    }
06075 
06076    for (;;) {
06077       unsigned int done = 0;
06078       switch ((dial_res = ast_dial_state(dial))) {
06079       case AST_DIAL_RESULT_ANSWERED:
06080          trunk_ref->trunk->chan = ast_dial_answered(dial);
06081       case AST_DIAL_RESULT_HANGUP:
06082       case AST_DIAL_RESULT_INVALID:
06083       case AST_DIAL_RESULT_FAILED:
06084       case AST_DIAL_RESULT_TIMEOUT:
06085       case AST_DIAL_RESULT_UNANSWERED:
06086          done = 1;
06087       case AST_DIAL_RESULT_TRYING:
06088       case AST_DIAL_RESULT_RINGING:
06089       case AST_DIAL_RESULT_PROGRESS:
06090       case AST_DIAL_RESULT_PROCEEDING:
06091          break;
06092       }
06093       if (done)
06094          break;
06095    }
06096 
06097    if (!trunk_ref->trunk->chan) {
06098       ast_mutex_lock(args->cond_lock);
06099       ast_cond_signal(args->cond);
06100       ast_mutex_unlock(args->cond_lock);
06101       ast_dial_join(dial);
06102       ast_dial_destroy(dial);
06103       return NULL;
06104    }
06105 
06106    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
06107    ast_set_flag64(&conf_flags, 
06108       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
06109       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
06110    conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan, NULL);
06111 
06112    ast_mutex_lock(args->cond_lock);
06113    ast_cond_signal(args->cond);
06114    ast_mutex_unlock(args->cond_lock);
06115 
06116    if (conf) {
06117       conf_run(trunk_ref->trunk->chan, conf, &conf_flags, NULL);
06118       dispose_conf(conf);
06119       conf = NULL;
06120    }
06121 
06122    /* If the trunk is going away, it is definitely now IDLE. */
06123    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06124 
06125    trunk_ref->trunk->chan = NULL;
06126    trunk_ref->trunk->on_hold = 0;
06127 
06128    ast_dial_join(dial);
06129    ast_dial_destroy(dial);
06130 
06131    return NULL;
06132 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Decrement reference counts, as incremented by find_conf().

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

01963 {
01964    int res = 0;
01965    int confno_int = 0;
01966 
01967    AST_LIST_LOCK(&confs);
01968    if (ast_atomic_dec_and_test(&conf->refcount)) {
01969       /* Take the conference room number out of an inuse state */
01970       if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
01971          conf_map[confno_int] = 0;
01972       }
01973       conf_free(conf);
01974       res = 1;
01975    }
01976    AST_LIST_UNLOCK(&confs);
01977 
01978    return res;
01979 }

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

Definition at line 4884 of file app_meetme.c.

References ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_log(), ast_mkdir(), ast_strlen_zero(), and LOG_WARNING.

Referenced by recordthread().

04885 {
04886    char *slash;
04887    if (ast_strlen_zero(filename)) {
04888       ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
04889    } else if (filename[0] != '/') {
04890       snprintf(buffer, PATH_MAX, "%s/meetme/%s", ast_config_AST_SPOOL_DIR, filename);
04891    } else {
04892       ast_copy_string(buffer, filename, PATH_MAX);
04893    }
04894 
04895    slash = buffer;
04896    if ((slash = strrchr(slash, '/'))) {
04897       *slash = '\0';
04898       ast_mkdir(buffer, 0777);
04899       *slash = '/';
04900    }
04901 }

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

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

Referenced by conf_exec(), and count_exec().

03994 {
03995    struct ast_config *cfg;
03996    struct ast_variable *var;
03997    struct ast_flags config_flags = { 0 };
03998    struct ast_conference *cnf;
03999 
04000    AST_DECLARE_APP_ARGS(args,
04001       AST_APP_ARG(confno);
04002       AST_APP_ARG(pin);
04003       AST_APP_ARG(pinadmin);
04004    );
04005 
04006    /* Check first in the conference list */
04007    ast_debug(1, "The requested confno is '%s'?\n", confno);
04008    AST_LIST_LOCK(&confs);
04009    AST_LIST_TRAVERSE(&confs, cnf, list) {
04010       ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
04011       if (!strcmp(confno, cnf->confno)) 
04012          break;
04013    }
04014    if (cnf) {
04015       cnf->refcount += refcount;
04016    }
04017    AST_LIST_UNLOCK(&confs);
04018 
04019    if (!cnf) {
04020       if (dynamic) {
04021          /* No need to parse meetme.conf */
04022          ast_debug(1, "Building dynamic conference '%s'\n", confno);
04023          if (dynamic_pin) {
04024             if (dynamic_pin[0] == 'q') {
04025                /* Query the user to enter a PIN */
04026                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
04027                   return NULL;
04028             }
04029             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan, NULL);
04030          } else {
04031             cnf = build_conf(confno, "", "", make, dynamic, refcount, chan, NULL);
04032          }
04033       } else {
04034          /* Check the config */
04035          cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
04036          if (!cfg) {
04037             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
04038             return NULL;
04039          } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04040             ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
04041             return NULL;
04042          }
04043 
04044          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
04045             char parse[MAX_SETTINGS];
04046 
04047             if (strcasecmp(var->name, "conf"))
04048                continue;
04049 
04050             ast_copy_string(parse, var->value, sizeof(parse));
04051 
04052             AST_STANDARD_APP_ARGS(args, parse);
04053             ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
04054             if (!strcasecmp(args.confno, confno)) {
04055                /* Bingo it's a valid conference */
04056                cnf = build_conf(args.confno,
04057                      S_OR(args.pin, ""),
04058                      S_OR(args.pinadmin, ""),
04059                      make, dynamic, refcount, chan, NULL);
04060                break;
04061             }
04062          }
04063          if (!var) {
04064             ast_debug(1, "%s isn't a valid conference\n", confno);
04065          }
04066          ast_config_destroy(cfg);
04067       }
04068    } else if (dynamic_pin) {
04069       /* Correct for the user selecting 'D' instead of 'd' to have
04070          someone join into a conference that has already been created
04071          with a pin. */
04072       if (dynamic_pin[0] == 'q') {
04073          dynamic_pin[0] = '\0';
04074       }
04075    }
04076 
04077    if (cnf) {
04078       if (confflags && !cnf->chan &&
04079           !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
04080           ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
04081          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
04082          ast_clear_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
04083       }
04084       
04085       if (confflags && !cnf->chan &&
04086           ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
04087          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
04088          ast_clear_flag64(confflags, CONFFLAG_RECORDCONF);
04089       }
04090    }
04091 
04092    return cnf;
04093 }

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

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

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

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

04463 {
04464    struct ast_conf_user *user = NULL;
04465    int cid;
04466 
04467    if (conf && callerident && sscanf(callerident, "%30d", &cid) == 1) {
04468       user = ao2_find(conf->usercontainer, &cid, 0);
04469       /* reference decremented later in admin_exec */
04470       return user;
04471    }
04472    return NULL;
04473 }

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

Definition at line 2059 of file app_meetme.c.

References CONF_HASJOIN.

Referenced by announce_thread().

02060 {
02061    switch (type) {
02062    case CONF_HASLEFT:
02063       return "conf-hasleft";
02064       break;
02065    case CONF_HASJOIN:
02066       return "conf-hasjoin";
02067       break;
02068    default:
02069       return "";
02070    }
02071 }

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

Definition at line 982 of file app_meetme.c.

00983 {
00984    if (x > 0)
00985       return "(talking)";
00986    else if (x < 0)
00987       return "(unmonitored)";
00988    else 
00989       return "(not talking)";
00990 }

static int load_config ( int  reload  )  [static]

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

06972 {
06973    load_config_meetme();
06974 
06975    if (reload && sla.thread != AST_PTHREADT_NULL) {
06976       sla_queue_event(SLA_EVENT_RELOAD);
06977       ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
06978          "and will be completed when the system is idle.\n");
06979       return 0;
06980    }
06981    
06982    return sla_load_config(0);
06983 }

static void load_config_meetme ( void   )  [static]

Definition at line 4994 of file app_meetme.c.

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

Referenced by load_config().

04995 {
04996    struct ast_config *cfg;
04997    struct ast_flags config_flags = { 0 };
04998    const char *val;
04999 
05000    if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
05001       return;
05002    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
05003       ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
05004       return;
05005    }
05006 
05007    audio_buffers = DEFAULT_AUDIO_BUFFERS;
05008 
05009    /*  Scheduling support is off by default */
05010    rt_schedule = 0;
05011    fuzzystart = 0;
05012    earlyalert = 0;
05013    endalert = 0;
05014    extendby = 0;
05015 
05016    /*  Logging of participants defaults to ON for compatibility reasons */
05017    rt_log_members = 1;  
05018 
05019    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
05020       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
05021          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
05022          audio_buffers = DEFAULT_AUDIO_BUFFERS;
05023       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
05024          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
05025             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
05026          audio_buffers = DEFAULT_AUDIO_BUFFERS;
05027       }
05028       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
05029          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
05030    }
05031 
05032    if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
05033       rt_schedule = ast_true(val);
05034    if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
05035       rt_log_members = ast_true(val);
05036    if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
05037       if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
05038          ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
05039          fuzzystart = 0;
05040       } 
05041    }
05042    if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
05043       if ((sscanf(val, "%30d", &earlyalert) != 1)) {
05044          ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
05045          earlyalert = 0;
05046       } 
05047    }
05048    if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
05049       if ((sscanf(val, "%30d", &endalert) != 1)) {
05050          ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
05051          endalert = 0;
05052       } 
05053    }
05054    if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
05055       if ((sscanf(val, "%30d", &extendby) != 1)) {
05056          ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
05057          extendby = 0;
05058       } 
05059    }
05060 
05061    ast_config_destroy(cfg);
05062 }

static int load_module ( void   )  [static]

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

07197 {
07198    int res = 0;
07199 
07200    res |= load_config(0);
07201 
07202    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07203    res |= ast_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute);
07204    res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute);
07205    res |= ast_manager_register_xml("MeetmeList", EVENT_FLAG_REPORTING, action_meetmelist);
07206    res |= ast_register_application_xml(app4, channel_admin_exec);
07207    res |= ast_register_application_xml(app3, admin_exec);
07208    res |= ast_register_application_xml(app2, count_exec);
07209    res |= ast_register_application_xml(app, conf_exec);
07210    res |= ast_register_application_xml(slastation_app, sla_station_exec);
07211    res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
07212 
07213 #ifdef TEST_FRAMEWORK
07214    AST_TEST_REGISTER(test_meetme_data_provider);
07215 #endif
07216    ast_data_register_multiple(meetme_data_providers, ARRAY_LEN(meetme_data_providers));
07217 
07218    res |= ast_devstate_prov_add("Meetme", meetmestate);
07219    res |= ast_devstate_prov_add("SLA", sla_state);
07220 
07221    res |= ast_custom_function_register(&meetme_info_acf);
07222    ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
07223 
07224    return res;
07225 }

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

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

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

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

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

07062 {
07063    struct ast_conference *cnf;
07064    struct ast_data *data_meetme, *data_meetme_users;
07065 
07066    AST_LIST_LOCK(&confs);
07067    AST_LIST_TRAVERSE(&confs, cnf, list) {
07068       data_meetme = ast_data_add_node(data_root, "meetme");
07069       if (!data_meetme) {
07070          continue;
07071       }
07072 
07073       ast_data_add_structure(ast_conference, data_meetme, cnf);
07074 
07075       if (ao2_container_count(cnf->usercontainer)) {
07076          data_meetme_users = ast_data_add_node(data_meetme, "users");
07077          if (!data_meetme_users) {
07078             ast_data_remove_node(data_root, data_meetme);
07079             continue;
07080          }
07081 
07082          ao2_callback(cnf->usercontainer, OBJ_NODATA, user_add_provider_cb, data_meetme_users); 
07083       }
07084 
07085       if (!ast_data_search_match(search, data_meetme)) {
07086          ast_data_remove_node(data_root, data_meetme);
07087       }
07088    }
07089    AST_LIST_UNLOCK(&confs);
07090 
07091    return 0;
07092 }

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

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

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

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

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

04734 {
04735    struct ast_conference *conf;
04736    struct ast_conf_user *user;
04737    const char *confid = astman_get_header(m, "Meetme");
04738    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
04739    int userno;
04740 
04741    if (ast_strlen_zero(confid)) {
04742       astman_send_error(s, m, "Meetme conference not specified");
04743       return 0;
04744    }
04745 
04746    if (ast_strlen_zero(userid)) {
04747       astman_send_error(s, m, "Meetme user number not specified");
04748       return 0;
04749    }
04750 
04751    userno = strtoul(userid, &userid, 10);
04752 
04753    if (*userid) {
04754       astman_send_error(s, m, "Invalid user number");
04755       return 0;
04756    }
04757 
04758    /* Look in the conference list */
04759    AST_LIST_LOCK(&confs);
04760    AST_LIST_TRAVERSE(&confs, conf, list) {
04761       if (!strcmp(confid, conf->confno))
04762          break;
04763    }
04764 
04765    if (!conf) {
04766       AST_LIST_UNLOCK(&confs);
04767       astman_send_error(s, m, "Meetme conference does not exist");
04768       return 0;
04769    }
04770 
04771    user = ao2_find(conf->usercontainer, &userno, 0);
04772 
04773    if (!user) {
04774       AST_LIST_UNLOCK(&confs);
04775       astman_send_error(s, m, "User number not found");
04776       return 0;
04777    }
04778 
04779    if (mute)
04780       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
04781    else
04782       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
04783 
04784    AST_LIST_UNLOCK(&confs);
04785 
04786    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);
04787 
04788    ao2_ref(user, -1);
04789    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
04790    return 0;
04791 }

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

Callback for devicestate providers.

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

04973 {
04974    struct ast_conference *conf;
04975 
04976    /* Find conference */
04977    AST_LIST_LOCK(&confs);
04978    AST_LIST_TRAVERSE(&confs, conf, list) {
04979       if (!strcmp(data, conf->confno))
04980          break;
04981    }
04982    AST_LIST_UNLOCK(&confs);
04983    if (!conf)
04984       return AST_DEVICE_INVALID;
04985 
04986 
04987    /* SKREP to fill */
04988    if (!conf->users)
04989       return AST_DEVICE_NOT_INUSE;
04990 
04991    return AST_DEVICE_INUSE;
04992 }

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

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

06322 {
06323    struct sla_ringing_trunk *ringing_trunk;
06324 
06325    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
06326       return NULL;
06327    
06328    ringing_trunk->trunk = trunk;
06329    ringing_trunk->ring_begin = ast_tvnow();
06330 
06331    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
06332 
06333    ast_mutex_lock(&sla.lock);
06334    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
06335    ast_mutex_unlock(&sla.lock);
06336 
06337    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06338 
06339    return ringing_trunk;
06340 }

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

Definition at line 4903 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_strlen_zero(), ast_waitfor(), ast_writefile(), ast_writestream(), f, filename_parse(), 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.

04904 {
04905    struct ast_conference *cnf = args;
04906    struct ast_frame *f = NULL;
04907    int flags;
04908    struct ast_filestream *s = NULL;
04909    int res = 0;
04910    int x;
04911    const char *oldrecordingfilename = NULL;
04912    char filename_buffer[PATH_MAX];
04913 
04914    if (!cnf || !cnf->lchan) {
04915       pthread_exit(0);
04916    }
04917 
04918    filename_buffer[0] = '\0';
04919    filename_parse(cnf->recordingfilename, filename_buffer);
04920 
04921    ast_stopstream(cnf->lchan);
04922    flags = O_CREAT | O_TRUNC | O_WRONLY;
04923 
04924 
04925    cnf->recording = MEETME_RECORD_ACTIVE;
04926    while (ast_waitfor(cnf->lchan, -1) > -1) {
04927       if (cnf->recording == MEETME_RECORD_TERMINATE) {
04928          AST_LIST_LOCK(&confs);
04929          AST_LIST_UNLOCK(&confs);
04930          break;
04931       }
04932       if (!s && !(ast_strlen_zero(filename_buffer)) && (filename_buffer != oldrecordingfilename)) {
04933          s = ast_writefile(filename_buffer, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
04934          oldrecordingfilename = filename_buffer;
04935       }
04936       
04937       f = ast_read(cnf->lchan);
04938       if (!f) {
04939          res = -1;
04940          break;
04941       }
04942       if (f->frametype == AST_FRAME_VOICE) {
04943          ast_mutex_lock(&cnf->listenlock);
04944          for (x = 0; x < AST_FRAME_BITS; x++) {
04945             /* Free any translations that have occured */
04946             if (cnf->transframe[x]) {
04947                ast_frfree(cnf->transframe[x]);
04948                cnf->transframe[x] = NULL;
04949             }
04950          }
04951          if (cnf->origframe)
04952             ast_frfree(cnf->origframe);
04953          cnf->origframe = ast_frdup(f);
04954          ast_mutex_unlock(&cnf->listenlock);
04955          if (s)
04956             res = ast_writestream(s, f);
04957          if (res) {
04958             ast_frfree(f);
04959             break;
04960          }
04961       }
04962       ast_frfree(f);
04963    }
04964    cnf->recording = MEETME_RECORD_OFF;
04965    if (s)
04966       ast_closestream(s);
04967    
04968    pthread_exit(0);
04969 }

static int reload ( void   )  [static]

Definition at line 7227 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

07228 {
07229    ast_unload_realtime("meetme");
07230    return load_config(1);
07231 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

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

01103 {
01104    signed char zero_volume = 0;
01105 
01106    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
01107    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
01108 }

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

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

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

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

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

05222 {
05223    struct sla_station *station;
05224    struct sla_trunk_ref *trunk_ref;
05225    struct ast_str *conf_name = ast_str_create(16);
05226    struct ast_flags64 conf_flags = { 0 };
05227    struct ast_conference *conf;
05228 
05229    {
05230       struct run_station_args *args = data;
05231       station = args->station;
05232       trunk_ref = args->trunk_ref;
05233       ast_mutex_lock(args->cond_lock);
05234       ast_cond_signal(args->cond);
05235       ast_mutex_unlock(args->cond_lock);
05236       /* args is no longer valid here. */
05237    }
05238 
05239    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
05240    ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
05241    ast_set_flag64(&conf_flags, 
05242       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05243    answer_trunk_chan(trunk_ref->chan);
05244    conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan, NULL);
05245    if (conf) {
05246       conf_run(trunk_ref->chan, conf, &conf_flags, NULL);
05247       dispose_conf(conf);
05248       conf = NULL;
05249    }
05250    trunk_ref->chan = NULL;
05251    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05252       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05253       ast_str_append(&conf_name, 0, ",K");
05254       admin_exec(NULL, ast_str_buffer(conf_name));
05255       trunk_ref->trunk->hold_stations = 0;
05256       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05257    }
05258 
05259    ast_dial_join(station->dial);
05260    ast_dial_destroy(station->dial);
05261    station->dial = NULL;
05262    ast_free(conf_name);
05263 
05264    return NULL;
05265 }

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

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

02136 {
02137    ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking",
02138       "Channel: %s\r\n"
02139       "Uniqueid: %s\r\n"
02140       "Meetme: %s\r\n"
02141       "Usernum: %d\r\n"
02142       "Status: %s\r\n",
02143       chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
02144 }

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

Definition at line 1031 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_TXGAIN, and user.

Referenced by tweak_listen_volume().

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

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

Definition at line 1019 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_RXGAIN, and user.

Referenced by conf_run(), and tweak_talk_volume().

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

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

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

Referenced by conf_run().

02147 {
02148    int last_talking = user->talking;
02149    if (last_talking == talking)
02150       return;
02151 
02152    user->talking = talking;
02153 
02154    if (monitor) {
02155       /* Check if talking state changed. Take care of -1 which means unmonitored */
02156       int was_talking = (last_talking > 0);
02157       int now_talking = (talking > 0);
02158       if (was_talking != now_talking) {
02159          send_talking_event(chan, conf, user, now_talking);
02160       }
02161    }
02162 }

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

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

06662 {
06663    struct sla_trunk *trunk;
06664    struct sla_trunk_ref *trunk_ref;
06665    struct sla_station_ref *station_ref;
06666    char *trunk_name, *options, *cur;
06667 
06668    options = ast_strdupa(var->value);
06669    trunk_name = strsep(&options, ",");
06670    
06671    AST_RWLIST_RDLOCK(&sla_trunks);
06672    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
06673       if (!strcasecmp(trunk->name, trunk_name))
06674          break;
06675    }
06676 
06677    AST_RWLIST_UNLOCK(&sla_trunks);
06678    if (!trunk) {
06679       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
06680       return;
06681    }
06682    if (!(trunk_ref = create_trunk_ref(trunk)))
06683       return;
06684    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
06685 
06686    while ((cur = strsep(&options, ","))) {
06687       char *name, *value = cur;
06688       name = strsep(&value, "=");
06689       if (!strcasecmp(name, "ringtimeout")) {
06690          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
06691             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
06692                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06693             trunk_ref->ring_timeout = 0;
06694          }
06695       } else if (!strcasecmp(name, "ringdelay")) {
06696          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
06697             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
06698                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06699             trunk_ref->ring_delay = 0;
06700          }
06701       } else {
06702          ast_log(LOG_WARNING, "Invalid option '%s' for "
06703             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
06704       }
06705    }
06706 
06707    if (!(station_ref = sla_create_station_ref(station))) {
06708       ast_free(trunk_ref);
06709       return;
06710    }
06711    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
06712    AST_RWLIST_WRLOCK(&sla_trunks);
06713    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
06714    AST_RWLIST_UNLOCK(&sla_trunks);
06715    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
06716 }

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

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

06719 {
06720    struct sla_station *station;
06721    struct ast_variable *var;
06722    const char *dev;
06723 
06724    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06725       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
06726       return -1;
06727    }
06728 
06729    if (!(station = ast_calloc_with_stringfields(1, struct sla_station, 32))) {
06730       return -1;
06731    }
06732 
06733    ast_string_field_set(station, name, cat);
06734    ast_string_field_set(station, device, dev);
06735 
06736    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06737       if (!strcasecmp(var->name, "trunk"))
06738          sla_add_trunk_to_station(station, var);
06739       else if (!strcasecmp(var->name, "autocontext"))
06740          ast_string_field_set(station, autocontext, var->value);
06741       else if (!strcasecmp(var->name, "ringtimeout")) {
06742          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
06743             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
06744                var->value, station->name);
06745             station->ring_timeout = 0;
06746          }
06747       } else if (!strcasecmp(var->name, "ringdelay")) {
06748          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
06749             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
06750                var->value, station->name);
06751             station->ring_delay = 0;
06752          }
06753       } else if (!strcasecmp(var->name, "hold")) {
06754          if (!strcasecmp(var->value, "private"))
06755             station->hold_access = SLA_HOLD_PRIVATE;
06756          else if (!strcasecmp(var->value, "open"))
06757             station->hold_access = SLA_HOLD_OPEN;
06758          else {
06759             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
06760                var->value, station->name);
06761          }
06762 
06763       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06764          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06765             var->name, var->lineno, SLA_CONFIG_FILE);
06766       }
06767    }
06768 
06769    if (!ast_strlen_zero(station->autocontext)) {
06770       struct ast_context *context;
06771       struct sla_trunk_ref *trunk_ref;
06772       context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
06773       if (!context) {
06774          ast_log(LOG_ERROR, "Failed to automatically find or create "
06775             "context '%s' for SLA!\n", station->autocontext);
06776          destroy_station(station);
06777          return -1;
06778       }
06779       /* The extension for when the handset goes off-hook.
06780        * exten => station1,1,SLAStation(station1) */
06781       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
06782          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
06783          ast_log(LOG_ERROR, "Failed to automatically create extension "
06784             "for trunk '%s'!\n", station->name);
06785          destroy_station(station);
06786          return -1;
06787       }
06788       AST_RWLIST_RDLOCK(&sla_trunks);
06789       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06790          char exten[AST_MAX_EXTENSION];
06791          char hint[AST_MAX_APP];
06792          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06793          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06794          /* Extension for this line button 
06795           * exten => station1_line1,1,SLAStation(station1_line1) */
06796          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
06797             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
06798             ast_log(LOG_ERROR, "Failed to automatically create extension "
06799                "for trunk '%s'!\n", station->name);
06800             destroy_station(station);
06801             return -1;
06802          }
06803          /* Hint for this line button 
06804           * exten => station1_line1,hint,SLA:station1_line1 */
06805          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
06806             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
06807             ast_log(LOG_ERROR, "Failed to automatically create hint "
06808                "for trunk '%s'!\n", station->name);
06809             destroy_station(station);
06810             return -1;
06811          }
06812       }
06813       AST_RWLIST_UNLOCK(&sla_trunks);
06814    }
06815 
06816    AST_RWLIST_WRLOCK(&sla_stations);
06817    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
06818    AST_RWLIST_UNLOCK(&sla_stations);
06819 
06820    return 0;
06821 }

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

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

06587 {
06588    struct sla_trunk *trunk;
06589    struct ast_variable *var;
06590    const char *dev;
06591 
06592    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06593       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
06594       return -1;
06595    }
06596 
06597    if (sla_check_device(dev)) {
06598       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
06599          cat, dev);
06600       return -1;
06601    }
06602 
06603    if (!(trunk = ast_calloc_with_stringfields(1, struct sla_trunk, 32))) {
06604       return -1;
06605    }
06606 
06607    ast_string_field_set(trunk, name, cat);
06608    ast_string_field_set(trunk, device, dev);
06609 
06610    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06611       if (!strcasecmp(var->name, "autocontext"))
06612          ast_string_field_set(trunk, autocontext, var->value);
06613       else if (!strcasecmp(var->name, "ringtimeout")) {
06614          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
06615             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
06616                var->value, trunk->name);
06617             trunk->ring_timeout = 0;
06618          }
06619       } else if (!strcasecmp(var->name, "barge"))
06620          trunk->barge_disabled = ast_false(var->value);
06621       else if (!strcasecmp(var->name, "hold")) {
06622          if (!strcasecmp(var->value, "private"))
06623             trunk->hold_access = SLA_HOLD_PRIVATE;
06624          else if (!strcasecmp(var->value, "open"))
06625             trunk->hold_access = SLA_HOLD_OPEN;
06626          else {
06627             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
06628                var->value, trunk->name);
06629          }
06630       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06631          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06632             var->name, var->lineno, SLA_CONFIG_FILE);
06633       }
06634    }
06635 
06636    if (!ast_strlen_zero(trunk->autocontext)) {
06637       struct ast_context *context;
06638       context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
06639       if (!context) {
06640          ast_log(LOG_ERROR, "Failed to automatically find or create "
06641             "context '%s' for SLA!\n", trunk->autocontext);
06642          destroy_trunk(trunk);
06643          return -1;
06644       }
06645       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
06646          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
06647          ast_log(LOG_ERROR, "Failed to automatically create extension "
06648             "for trunk '%s'!\n", trunk->name);
06649          destroy_trunk(trunk);
06650          return -1;
06651       }
06652    }
06653 
06654    AST_RWLIST_WRLOCK(&sla_trunks);
06655    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
06656    AST_RWLIST_UNLOCK(&sla_trunks);
06657 
06658    return 0;
06659 }

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

05834 {
05835    struct sla_station *station;
05836    int res = 0;
05837 
05838    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05839       struct sla_ringing_trunk *ringing_trunk;
05840       int time_left;
05841 
05842       /* Ignore stations already ringing */
05843       if (sla_check_ringing_station(station))
05844          continue;
05845 
05846       /* Ignore stations already on a call */
05847       if (sla_check_inuse_station(station))
05848          continue;
05849 
05850       /* Ignore stations that don't have one of their trunks ringing */
05851       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
05852          continue;
05853 
05854       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
05855          continue;
05856 
05857       /* If there is no time left, then the station needs to start ringing.
05858        * Return non-zero so that an event will be queued up an event to 
05859        * make that happen. */
05860       if (time_left <= 0) {
05861          res = 1;
05862          continue;
05863       }
05864 
05865       if (time_left < *timeout)
05866          *timeout = time_left;
05867    }
05868 
05869    return res;
05870 }

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

05751 {
05752    struct sla_ringing_trunk *ringing_trunk;
05753    struct sla_ringing_station *ringing_station;
05754    int res = 0;
05755 
05756    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05757       unsigned int ring_timeout = 0;
05758       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
05759       struct sla_trunk_ref *trunk_ref;
05760 
05761       /* If there are any ring timeouts specified for a specific trunk
05762        * on the station, then use the highest per-trunk ring timeout.
05763        * Otherwise, use the ring timeout set for the entire station. */
05764       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05765          struct sla_station_ref *station_ref;
05766          int trunk_time_elapsed, trunk_time_left;
05767 
05768          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05769             if (ringing_trunk->trunk == trunk_ref->trunk)
05770                break;
05771          }
05772          if (!ringing_trunk)
05773             continue;
05774 
05775          /* If there is a trunk that is ringing without a timeout, then the
05776           * only timeout that could matter is a global station ring timeout. */
05777          if (!trunk_ref->ring_timeout)
05778             break;
05779 
05780          /* This trunk on this station is ringing and has a timeout.
05781           * However, make sure this trunk isn't still ringing from a
05782           * previous timeout.  If so, don't consider it. */
05783          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
05784             if (station_ref->station == ringing_station->station)
05785                break;
05786          }
05787          if (station_ref)
05788             continue;
05789 
05790          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05791          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
05792          if (trunk_time_left > final_trunk_time_left)
05793             final_trunk_time_left = trunk_time_left;
05794       }
05795 
05796       /* No timeout was found for ringing trunks, and no timeout for the entire station */
05797       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
05798          continue;
05799 
05800       /* Compute how much time is left for a global station timeout */
05801       if (ringing_station->station->ring_timeout) {
05802          ring_timeout = ringing_station->station->ring_timeout;
05803          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
05804          time_left = (ring_timeout * 1000) - time_elapsed;
05805       }
05806 
05807       /* If the time left based on the per-trunk timeouts is smaller than the
05808        * global station ring timeout, use that. */
05809       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
05810          time_left = final_trunk_time_left;
05811 
05812       /* If there is no time left, the station needs to stop ringing */
05813       if (time_left <= 0) {
05814          AST_LIST_REMOVE_CURRENT(entry);
05815          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
05816          res = 1;
05817          continue;
05818       }
05819 
05820       /* There is still some time left for this station to ring, so save that
05821        * timeout if it is the first event scheduled to occur */
05822       if (time_left < *timeout)
05823          *timeout = time_left;
05824    }
05825    AST_LIST_TRAVERSE_SAFE_END;
05826 
05827    return res;
05828 }

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

05721 {
05722    struct sla_ringing_trunk *ringing_trunk;
05723    int res = 0;
05724 
05725    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05726       int time_left, time_elapsed;
05727       if (!ringing_trunk->trunk->ring_timeout)
05728          continue;
05729       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05730       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
05731       if (time_left <= 0) {
05732          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
05733          AST_LIST_REMOVE_CURRENT(entry);
05734          sla_stop_ringing_trunk(ringing_trunk);
05735          res = 1;
05736          continue;
05737       }
05738       if (time_left < *timeout)
05739          *timeout = time_left;
05740    }
05741    AST_LIST_TRAVERSE_SAFE_END;
05742 
05743    return res;
05744 }

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

05191 {
05192    struct sla_station *station;
05193    struct sla_trunk_ref *trunk_ref;
05194 
05195    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05196       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05197          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
05198             || trunk_ref == exclude)
05199             continue;
05200          trunk_ref->state = state;
05201          ast_devstate_changed(sla_state_to_devstate(state), 
05202             "SLA:%s_%s", station->name, trunk->name);
05203          break;
05204       }
05205    }
05206 }

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

Definition at line 6573 of file app_meetme.c.

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

Referenced by sla_build_trunk().

06574 {
06575    char *tech, *tech_data;
06576 
06577    tech_data = ast_strdupa(device);
06578    tech = strsep(&tech_data, "/");
06579 
06580    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
06581       return -1;
06582 
06583    return 0;
06584 }

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

05470 {
05471    struct sla_failed_station *failed_station;
05472    int res = 0;
05473 
05474    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
05475       if (station != failed_station->station)
05476          continue;
05477       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
05478          AST_LIST_REMOVE_CURRENT(entry);
05479          ast_free(failed_station);
05480          break;
05481       }
05482       res = 1;
05483    }
05484    AST_LIST_TRAVERSE_SAFE_END
05485 
05486    return res;
05487 }

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

Check to see if a station is in use.

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

05555 {
05556    struct sla_trunk_ref *trunk_ref;
05557 
05558    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05559       if (trunk_ref->chan)
05560          return 1;
05561    }
05562 
05563    return 0;
05564 }

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

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

Referenced by sla_thread().

05913 {
05914    struct sla_station *station;
05915    struct sla_trunk *trunk;
05916 
05917    ast_mutex_lock(&sla.lock);
05918 
05919    if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
05920       || !AST_LIST_EMPTY(&sla.ringing_stations)) {
05921       ast_mutex_unlock(&sla.lock);
05922       return;
05923    }
05924 
05925    AST_RWLIST_RDLOCK(&sla_stations);
05926    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
05927       if (station->ref_count)
05928          break;
05929    }
05930    AST_RWLIST_UNLOCK(&sla_stations);
05931    if (station) {
05932       ast_mutex_unlock(&sla.lock);
05933       return;
05934    }
05935 
05936    AST_RWLIST_RDLOCK(&sla_trunks);
05937    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05938       if (trunk->ref_count)
05939          break;
05940    }
05941    AST_RWLIST_UNLOCK(&sla_trunks);
05942    if (trunk) {
05943       ast_mutex_unlock(&sla.lock);
05944       return;
05945    }
05946 
05947    /* yay */
05948    sla_load_config(1);
05949    sla.reload = 0;
05950 
05951    ast_mutex_unlock(&sla.lock);
05952 }

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

05455 {
05456    struct sla_ringing_station *ringing_station;
05457 
05458    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
05459       if (station == ringing_station->station)
05460          return 1;
05461    }
05462 
05463    return 0;
05464 }

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

05586 {
05587    struct sla_trunk_ref *trunk_ref;
05588    unsigned int delay = UINT_MAX;
05589    int time_left, time_elapsed;
05590 
05591    if (!ringing_trunk)
05592       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
05593    else
05594       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
05595 
05596    if (!ringing_trunk || !trunk_ref)
05597       return delay;
05598 
05599    /* If this station has a ring delay specific to the highest priority
05600     * ringing trunk, use that.  Otherwise, use the ring delay specified
05601     * globally for the station. */
05602    delay = trunk_ref->ring_delay;
05603    if (!delay)
05604       delay = station->ring_delay;
05605    if (!delay)
05606       return INT_MAX;
05607 
05608    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05609    time_left = (delay * 1000) - time_elapsed;
05610 
05611    return time_left;
05612 }

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

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

05096 {
05097    struct sla_station_ref *station_ref;
05098    struct sla_trunk_ref *trunk_ref;
05099 
05100    /* For each station that has this call on hold, check for private hold. */
05101    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
05102       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
05103          if (trunk_ref->trunk != trunk || station_ref->station == station)
05104             continue;
05105          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
05106             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
05107             return 1;
05108          return 0;
05109       }
05110    }
05111 
05112    return 0;
05113 }

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

05327 {
05328    struct sla_station_ref *timed_out_station;
05329 
05330    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
05331       if (station == timed_out_station->station)
05332          return 1;
05333    }
05334 
05335    return 0;
05336 }

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

06137 {
06138    struct sla_trunk_ref *trunk_ref = NULL;
06139 
06140    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06141       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
06142          break;
06143    }
06144 
06145    return trunk_ref;
06146 }

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

05348 {
05349    struct sla_trunk_ref *s_trunk_ref;
05350    struct sla_ringing_trunk *ringing_trunk = NULL;
05351 
05352    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
05353       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05354          /* Make sure this is the trunk we're looking for */
05355          if (s_trunk_ref->trunk != ringing_trunk->trunk)
05356             continue;
05357 
05358          /* This trunk on the station is ringing.  But, make sure this station
05359           * didn't already time out while this trunk was ringing. */
05360          if (sla_check_timed_out_station(ringing_trunk, station))
05361             continue;
05362 
05363          if (rm)
05364             AST_LIST_REMOVE_CURRENT(entry);
05365 
05366          if (trunk_ref)
05367             *trunk_ref = s_trunk_ref;
05368 
05369          break;
05370       }
05371       AST_LIST_TRAVERSE_SAFE_END;
05372    
05373       if (ringing_trunk)
05374          break;
05375    }
05376 
05377    return ringing_trunk;
05378 }

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

Definition at line 5159 of file app_meetme.c.

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

Referenced by sla_ring_station().

05160 {
05161    struct sla_ringing_station *ringing_station;
05162 
05163    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
05164       return NULL;
05165 
05166    ringing_station->station = station;
05167    ringing_station->ring_begin = ast_tvnow();
05168 
05169    return ringing_station;
05170 }

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

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

05148 {
05149    struct sla_station_ref *station_ref;
05150 
05151    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
05152       return NULL;
05153 
05154    station_ref->station = station;
05155 
05156    return station_ref;
05157 }

static void sla_destroy ( void   )  [static]

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

06544 {
06545    struct sla_trunk *trunk;
06546    struct sla_station *station;
06547 
06548    AST_RWLIST_WRLOCK(&sla_trunks);
06549    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
06550       destroy_trunk(trunk);
06551    AST_RWLIST_UNLOCK(&sla_trunks);
06552 
06553    AST_RWLIST_WRLOCK(&sla_stations);
06554    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
06555       destroy_station(station);
06556    AST_RWLIST_UNLOCK(&sla_stations);
06557 
06558    if (sla.thread != AST_PTHREADT_NULL) {
06559       ast_mutex_lock(&sla.lock);
06560       sla.stop = 1;
06561       ast_cond_signal(&sla.cond);
06562       ast_mutex_unlock(&sla.lock);
06563       pthread_join(sla.thread, NULL);
06564    }
06565 
06566    /* Drop any created contexts from the dialplan */
06567    ast_context_destroy(NULL, sla_registrar);
06568 
06569    ast_mutex_destroy(&sla.lock);
06570    ast_cond_destroy(&sla.cond);
06571 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 5317 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

05318 {
05319    sla_queue_event(SLA_EVENT_DIAL_STATE);
05320 }

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

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

Referenced by sla_station_exec().

05083 {
05084    struct sla_station *station = NULL;
05085 
05086    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
05087       if (!strcasecmp(station->name, name))
05088          break;
05089    }
05090 
05091    return station;
05092 }

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

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

Referenced by sla_trunk_exec().

05068 {
05069    struct sla_trunk *trunk = NULL;
05070 
05071    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05072       if (!strcasecmp(trunk->name, name))
05073          break;
05074    }
05075 
05076    return trunk;
05077 }

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

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

05568 {
05569    struct sla_trunk_ref *trunk_ref = NULL;
05570 
05571    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05572       if (trunk_ref->trunk == trunk)
05573          break;
05574    }
05575 
05576    return trunk_ref;
05577 }

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

05124 {
05125    struct sla_trunk_ref *trunk_ref = NULL;
05126 
05127    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05128       if (strcasecmp(trunk_ref->trunk->name, name))
05129          continue;
05130 
05131       if ( (trunk_ref->trunk->barge_disabled 
05132          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
05133          (trunk_ref->trunk->hold_stations 
05134          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
05135          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
05136          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
05137       {
05138          trunk_ref = NULL;
05139       }
05140 
05141       break;
05142    }
05143 
05144    return trunk_ref;
05145 }

static void sla_handle_dial_state_event ( void   )  [static]

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

05381 {
05382    struct sla_ringing_station *ringing_station;
05383 
05384    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05385       struct sla_trunk_ref *s_trunk_ref = NULL;
05386       struct sla_ringing_trunk *ringing_trunk = NULL;
05387       struct run_station_args args;
05388       enum ast_dial_result dial_res;
05389       pthread_t dont_care;
05390       ast_mutex_t cond_lock;
05391       ast_cond_t cond;
05392 
05393       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
05394       case AST_DIAL_RESULT_HANGUP:
05395       case AST_DIAL_RESULT_INVALID:
05396       case AST_DIAL_RESULT_FAILED:
05397       case AST_DIAL_RESULT_TIMEOUT:
05398       case AST_DIAL_RESULT_UNANSWERED:
05399          AST_LIST_REMOVE_CURRENT(entry);
05400          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
05401          break;
05402       case AST_DIAL_RESULT_ANSWERED:
05403          AST_LIST_REMOVE_CURRENT(entry);
05404          /* Find the appropriate trunk to answer. */
05405          ast_mutex_lock(&sla.lock);
05406          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
05407          ast_mutex_unlock(&sla.lock);
05408          if (!ringing_trunk) {
05409             ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
05410             break;
05411          }
05412          /* Track the channel that answered this trunk */
05413          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
05414          /* Actually answer the trunk */
05415          answer_trunk_chan(ringing_trunk->trunk->chan);
05416          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05417          /* Now, start a thread that will connect this station to the trunk.  The rest of
05418           * the code here sets up the thread and ensures that it is able to save the arguments
05419           * before they are no longer valid since they are allocated on the stack. */
05420          args.trunk_ref = s_trunk_ref;
05421          args.station = ringing_station->station;
05422          args.cond = &cond;
05423          args.cond_lock = &cond_lock;
05424          ast_free(ringing_trunk);
05425          ast_free(ringing_station);
05426          ast_mutex_init(&cond_lock);
05427          ast_cond_init(&cond, NULL);
05428          ast_mutex_lock(&cond_lock);
05429          ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
05430          ast_cond_wait(&cond, &cond_lock);
05431          ast_mutex_unlock(&cond_lock);
05432          ast_mutex_destroy(&cond_lock);
05433          ast_cond_destroy(&cond);
05434          break;
05435       case AST_DIAL_RESULT_TRYING:
05436       case AST_DIAL_RESULT_RINGING:
05437       case AST_DIAL_RESULT_PROGRESS:
05438       case AST_DIAL_RESULT_PROCEEDING:
05439          break;
05440       }
05441       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
05442          /* Queue up reprocessing ringing trunks, and then ringing stations again */
05443          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05444          sla_queue_event(SLA_EVENT_DIAL_STATE);
05445          break;
05446       }
05447    }
05448    AST_LIST_TRAVERSE_SAFE_END;
05449 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

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

05697 {
05698    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
05699    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
05700    ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
05701       event->station->name, event->trunk_ref->trunk->name);
05702    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
05703       INACTIVE_TRUNK_REFS, event->trunk_ref);
05704 
05705    if (event->trunk_ref->trunk->active_stations == 1) {
05706       /* The station putting it on hold is the only one on the call, so start
05707        * Music on hold to the trunk. */
05708       event->trunk_ref->trunk->on_hold = 1;
05709       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
05710    }
05711 
05712    ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
05713    event->trunk_ref->chan = NULL;
05714 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 5686 of file app_meetme.c.

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

Referenced by sla_thread().

05687 {
05688    ast_mutex_lock(&sla.lock);
05689    sla_ring_stations();
05690    ast_mutex_unlock(&sla.lock);
05691 
05692    /* Find stations that shouldn't be ringing anymore. */
05693    sla_hangup_stations();
05694 }

static void sla_hangup_stations ( void   )  [static]

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

05659 {
05660    struct sla_trunk_ref *trunk_ref;
05661    struct sla_ringing_station *ringing_station;
05662 
05663    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05664       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05665          struct sla_ringing_trunk *ringing_trunk;
05666          ast_mutex_lock(&sla.lock);
05667          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05668             if (trunk_ref->trunk == ringing_trunk->trunk)
05669                break;
05670          }
05671          ast_mutex_unlock(&sla.lock);
05672          if (ringing_trunk)
05673             break;
05674       }
05675       if (!trunk_ref) {
05676          AST_LIST_REMOVE_CURRENT(entry);
05677          ast_dial_join(ringing_station->station->dial);
05678          ast_dial_destroy(ringing_station->station->dial);
05679          ringing_station->station->dial = NULL;
05680          ast_free(ringing_station);
05681       }
05682    }
05683    AST_LIST_TRAVERSE_SAFE_END
05684 }

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

Definition at line 1607 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01608 {
01609    const char *hold = "Unknown";
01610 
01611    switch (hold_access) {
01612    case SLA_HOLD_OPEN:
01613       hold = "Open";
01614       break;
01615    case SLA_HOLD_PRIVATE:
01616       hold = "Private";
01617    default:
01618       break;
01619    }
01620 
01621    return hold;
01622 }

static int sla_load_config ( int  reload  )  [static]

Definition at line 6823 of file app_meetme.c.

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

Referenced by load_config(), and sla_check_reload().

06824 {
06825    struct ast_config *cfg;
06826    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06827    const char *cat = NULL;
06828    int res = 0;
06829    const char *val;
06830 
06831    if (!reload) {
06832       ast_mutex_init(&sla.lock);
06833       ast_cond_init(&sla.cond, NULL);
06834    }
06835 
06836    if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
06837       return 0; /* Treat no config as normal */
06838    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06839       return 0;
06840    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06841       ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format.  Aborting.\n");
06842       return 0;
06843    }
06844 
06845    if (reload) {
06846       struct sla_station *station;
06847       struct sla_trunk *trunk;
06848 
06849       /* We need to actually delete the previous versions of trunks and stations now */
06850       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_stations, station, entry) {
06851          AST_RWLIST_REMOVE_CURRENT(entry);
06852          ast_free(station);
06853       }
06854       AST_RWLIST_TRAVERSE_SAFE_END;
06855 
06856       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&sla_trunks, trunk, entry) {
06857          AST_RWLIST_REMOVE_CURRENT(entry);
06858          ast_free(trunk);
06859       }
06860       AST_RWLIST_TRAVERSE_SAFE_END;
06861    }
06862 
06863    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
06864       sla.attempt_callerid = ast_true(val);
06865 
06866    while ((cat = ast_category_browse(cfg, cat)) && !res) {
06867       const char *type;
06868       if (!strcasecmp(cat, "general"))
06869          continue;
06870       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
06871          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
06872             SLA_CONFIG_FILE);
06873          continue;
06874       }
06875       if (!strcasecmp(type, "trunk"))
06876          res = sla_build_trunk(cfg, cat);
06877       else if (!strcasecmp(type, "station"))
06878          res = sla_build_station(cfg, cat);
06879       else {
06880          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
06881             SLA_CONFIG_FILE, type);
06882       }
06883    }
06884 
06885    ast_config_destroy(cfg);
06886 
06887    /* Even if we don't have any stations, we may after a reload and we need to
06888     * be able to process the SLA_EVENT_RELOAD event in that case */
06889    if (sla.thread == AST_PTHREADT_NULL && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_trunks))) {
06890       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
06891    }
06892 
06893    return res;
06894 }

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

05875 {
05876    unsigned int timeout = UINT_MAX;
05877    struct timeval wait;
05878    unsigned int change_made = 0;
05879 
05880    /* Check for ring timeouts on ringing trunks */
05881    if (sla_calc_trunk_timeouts(&timeout))
05882       change_made = 1;
05883 
05884    /* Check for ring timeouts on ringing stations */
05885    if (sla_calc_station_timeouts(&timeout))
05886       change_made = 1;
05887 
05888    /* Check for station ring delays */
05889    if (sla_calc_station_delays(&timeout))
05890       change_made = 1;
05891 
05892    /* queue reprocessing of ringing trunks */
05893    if (change_made)
05894       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
05895 
05896    /* No timeout */
05897    if (timeout == UINT_MAX)
05898       return 0;
05899 
05900    if (ts) {
05901       wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
05902       ts->tv_sec = wait.tv_sec;
05903       ts->tv_nsec = wait.tv_usec * 1000;
05904    }
05905 
05906    return 1;
05907 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

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

01923 {
01924    sla_queue_event_full(type, NULL, NULL, 1);
01925 }

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

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

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

01892 {
01893    struct sla_event *event;
01894 
01895    if (sla.thread == AST_PTHREADT_NULL) {
01896       return;
01897    }
01898 
01899    if (!(event = ast_calloc(1, sizeof(*event))))
01900       return;
01901 
01902    event->type = type;
01903    event->trunk_ref = trunk_ref;
01904    event->station = station;
01905 
01906    if (!lock) {
01907       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01908       return;
01909    }
01910 
01911    ast_mutex_lock(&sla.lock);
01912    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01913    ast_cond_signal(&sla.cond);
01914    ast_mutex_unlock(&sla.lock);
01915 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1917 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01918 {
01919    sla_queue_event_full(type, NULL, NULL, 0);
01920 }

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

05493 {
05494    char *tech, *tech_data;
05495    struct ast_dial *dial;
05496    struct sla_ringing_station *ringing_station;
05497    enum ast_dial_result res;
05498    int caller_is_saved;
05499    struct ast_party_caller caller;
05500 
05501    if (!(dial = ast_dial_create()))
05502       return -1;
05503 
05504    ast_dial_set_state_callback(dial, sla_dial_state_callback);
05505    tech_data = ast_strdupa(station->device);
05506    tech = strsep(&tech_data, "/");
05507 
05508    if (ast_dial_append(dial, tech, tech_data) == -1) {
05509       ast_dial_destroy(dial);
05510       return -1;
05511    }
05512 
05513    /* Do we need to save off the caller ID data? */
05514    caller_is_saved = 0;
05515    if (!sla.attempt_callerid) {
05516       caller_is_saved = 1;
05517       caller = ringing_trunk->trunk->chan->caller;
05518       ast_party_caller_init(&ringing_trunk->trunk->chan->caller);
05519    }
05520 
05521    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
05522    
05523    /* Restore saved caller ID */
05524    if (caller_is_saved) {
05525       ast_party_caller_free(&ringing_trunk->trunk->chan->caller);
05526       ringing_trunk->trunk->chan->caller = caller;
05527    }
05528    
05529    if (res != AST_DIAL_RESULT_TRYING) {
05530       struct sla_failed_station *failed_station;
05531       ast_dial_destroy(dial);
05532       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
05533          return -1;
05534       failed_station->station = station;
05535       failed_station->last_try = ast_tvnow();
05536       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
05537       return -1;
05538    }
05539    if (!(ringing_station = sla_create_ringing_station(station))) {
05540       ast_dial_join(dial);
05541       ast_dial_destroy(dial);
05542       return -1;
05543    }
05544 
05545    station->dial = dial;
05546 
05547    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
05548 
05549    return 0;
05550 }

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

05618 {
05619    struct sla_station_ref *station_ref;
05620    struct sla_ringing_trunk *ringing_trunk;
05621 
05622    /* Make sure that every station that uses at least one of the ringing
05623     * trunks, is ringing. */
05624    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05625       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
05626          int time_left;
05627 
05628          /* Is this station already ringing? */
05629          if (sla_check_ringing_station(station_ref->station))
05630             continue;
05631 
05632          /* Is this station already in a call? */
05633          if (sla_check_inuse_station(station_ref->station))
05634             continue;
05635 
05636          /* Did we fail to dial this station earlier?  If so, has it been
05637           * a minute since we tried? */
05638          if (sla_check_failed_station(station_ref->station))
05639             continue;
05640 
05641          /* If this station already timed out while this trunk was ringing,
05642           * do not dial it again for this ringing trunk. */
05643          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
05644             continue;
05645 
05646          /* Check for a ring delay in progress */
05647          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
05648          if (time_left != INT_MAX && time_left > 0)
05649             continue;
05650 
05651          /* It is time to make this station begin to ring.  Do it! */
05652          sla_ring_station(ringing_trunk, station_ref->station);
05653       }
05654    }
05655    /* Now, all of the stations that should be ringing, are ringing. */
05656 }

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

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

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

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

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

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

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

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

06468 {
06469    char *buf, *station_name, *trunk_name;
06470    struct sla_station *station;
06471    struct sla_trunk_ref *trunk_ref;
06472    enum ast_device_state res = AST_DEVICE_INVALID;
06473 
06474    trunk_name = buf = ast_strdupa(data);
06475    station_name = strsep(&trunk_name, "_");
06476 
06477    AST_RWLIST_RDLOCK(&sla_stations);
06478    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
06479       if (strcasecmp(station_name, station->name))
06480          continue;
06481       AST_RWLIST_RDLOCK(&sla_trunks);
06482       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06483          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
06484             break;
06485       }
06486       if (!trunk_ref) {
06487          AST_RWLIST_UNLOCK(&sla_trunks);
06488          break;
06489       }
06490       res = sla_state_to_devstate(trunk_ref->state);
06491       AST_RWLIST_UNLOCK(&sla_trunks);
06492    }
06493    AST_RWLIST_UNLOCK(&sla_stations);
06494 
06495    if (res == AST_DEVICE_INVALID) {
06496       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
06497          trunk_name, station_name);
06498    }
06499 
06500    return res;
06501 }

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

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

05173 {
05174    switch (state) {
05175    case SLA_TRUNK_STATE_IDLE:
05176       return AST_DEVICE_NOT_INUSE;
05177    case SLA_TRUNK_STATE_RINGING:
05178       return AST_DEVICE_RINGING;
05179    case SLA_TRUNK_STATE_UP:
05180       return AST_DEVICE_INUSE;
05181    case SLA_TRUNK_STATE_ONHOLD:
05182    case SLA_TRUNK_STATE_ONHOLD_BYME:
05183       return AST_DEVICE_ONHOLD;
05184    }
05185 
05186    return AST_DEVICE_UNKNOWN;
05187 }

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

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

06149 {
06150    char *station_name, *trunk_name;
06151    struct sla_station *station;
06152    struct sla_trunk_ref *trunk_ref = NULL;
06153    char conf_name[MAX_CONFNUM];
06154    struct ast_flags64 conf_flags = { 0 };
06155    struct ast_conference *conf;
06156 
06157    if (ast_strlen_zero(data)) {
06158       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
06159       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06160       return 0;
06161    }
06162 
06163    trunk_name = ast_strdupa(data);
06164    station_name = strsep(&trunk_name, "_");
06165 
06166    if (ast_strlen_zero(station_name)) {
06167       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
06168       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06169       return 0;
06170    }
06171 
06172    AST_RWLIST_RDLOCK(&sla_stations);
06173    station = sla_find_station(station_name);
06174    if (station)
06175       ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
06176    AST_RWLIST_UNLOCK(&sla_stations);
06177 
06178    if (!station) {
06179       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
06180       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
06181       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06182       return 0;
06183    }
06184 
06185    AST_RWLIST_RDLOCK(&sla_trunks);
06186    if (!ast_strlen_zero(trunk_name)) {
06187       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
06188    } else
06189       trunk_ref = sla_choose_idle_trunk(station);
06190    AST_RWLIST_UNLOCK(&sla_trunks);
06191 
06192    if (!trunk_ref) {
06193       if (ast_strlen_zero(trunk_name))
06194          ast_log(LOG_NOTICE, "No trunks available for call.\n");
06195       else {
06196          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
06197             "'%s' due to access controls.\n", trunk_name);
06198       }
06199       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
06200       ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06201       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06202       return 0;
06203    }
06204 
06205    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
06206       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
06207          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06208       else {
06209          trunk_ref->state = SLA_TRUNK_STATE_UP;
06210          ast_devstate_changed(AST_DEVICE_INUSE, 
06211             "SLA:%s_%s", station->name, trunk_ref->trunk->name);
06212       }
06213    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
06214       struct sla_ringing_trunk *ringing_trunk;
06215 
06216       ast_mutex_lock(&sla.lock);
06217       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
06218          if (ringing_trunk->trunk == trunk_ref->trunk) {
06219             AST_LIST_REMOVE_CURRENT(entry);
06220             break;
06221          }
06222       }
06223       AST_LIST_TRAVERSE_SAFE_END
06224       ast_mutex_unlock(&sla.lock);
06225 
06226       if (ringing_trunk) {
06227          answer_trunk_chan(ringing_trunk->trunk->chan);
06228          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06229 
06230          free(ringing_trunk);
06231 
06232          /* Queue up reprocessing ringing trunks, and then ringing stations again */
06233          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06234          sla_queue_event(SLA_EVENT_DIAL_STATE);
06235       }
06236    }
06237 
06238    trunk_ref->chan = chan;
06239 
06240    if (!trunk_ref->trunk->chan) {
06241       ast_mutex_t cond_lock;
06242       ast_cond_t cond;
06243       pthread_t dont_care;
06244       struct dial_trunk_args args = {
06245          .trunk_ref = trunk_ref,
06246          .station = station,
06247          .cond_lock = &cond_lock,
06248          .cond = &cond,
06249       };
06250       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06251       /* Create a thread to dial the trunk and dump it into the conference.
06252        * However, we want to wait until the trunk has been dialed and the
06253        * conference is created before continuing on here. */
06254       ast_autoservice_start(chan);
06255       ast_mutex_init(&cond_lock);
06256       ast_cond_init(&cond, NULL);
06257       ast_mutex_lock(&cond_lock);
06258       ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
06259       ast_cond_wait(&cond, &cond_lock);
06260       ast_mutex_unlock(&cond_lock);
06261       ast_mutex_destroy(&cond_lock);
06262       ast_cond_destroy(&cond);
06263       ast_autoservice_stop(chan);
06264       if (!trunk_ref->trunk->chan) {
06265          ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
06266          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
06267          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06268          trunk_ref->chan = NULL;
06269          ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06270          sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06271          return 0;
06272       }
06273    }
06274 
06275    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
06276       trunk_ref->trunk->on_hold) {
06277       trunk_ref->trunk->on_hold = 0;
06278       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
06279       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
06280    }
06281 
06282    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
06283    ast_set_flag64(&conf_flags, 
06284       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
06285    ast_answer(chan);
06286    conf = build_conf(conf_name, "", "", 0, 0, 1, chan, NULL);
06287    if (conf) {
06288       conf_run(chan, conf, &conf_flags, NULL);
06289       dispose_conf(conf);
06290       conf = NULL;
06291    }
06292    trunk_ref->chan = NULL;
06293    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
06294       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
06295       strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
06296       admin_exec(NULL, conf_name);
06297       trunk_ref->trunk->hold_stations = 0;
06298       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06299    }
06300    
06301    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
06302 
06303    ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
06304    sla_queue_event(SLA_EVENT_CHECK_RELOAD);
06305 
06306    return 0;
06307 }

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

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

05284 {
05285    struct sla_ringing_trunk *ringing_trunk;
05286    struct sla_trunk_ref *trunk_ref;
05287    struct sla_station_ref *station_ref;
05288 
05289    ast_dial_join(ringing_station->station->dial);
05290    ast_dial_destroy(ringing_station->station->dial);
05291    ringing_station->station->dial = NULL;
05292 
05293    if (hangup == SLA_STATION_HANGUP_NORMAL)
05294       goto done;
05295 
05296    /* If the station is being hung up because of a timeout, then add it to the
05297     * list of timed out stations on each of the ringing trunks.  This is so
05298     * that when doing further processing to figure out which stations should be
05299     * ringing, which trunk to answer, determining timeouts, etc., we know which
05300     * ringing trunks we should ignore. */
05301    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05302       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05303          if (ringing_trunk->trunk == trunk_ref->trunk)
05304             break;
05305       }
05306       if (!trunk_ref)
05307          continue;
05308       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
05309          continue;
05310       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
05311    }
05312 
05313 done:
05314    ast_free(ringing_station);
05315 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

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

05268 {
05269    char buf[80];
05270    struct sla_station_ref *station_ref;
05271 
05272    snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
05273    admin_exec(NULL, buf);
05274    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05275 
05276    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
05277       ast_free(station_ref);
05278 
05279    ast_free(ringing_trunk);
05280 }

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

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

05955 {
05956    struct sla_failed_station *failed_station;
05957    struct sla_ringing_station *ringing_station;
05958 
05959    ast_mutex_lock(&sla.lock);
05960 
05961    while (!sla.stop) {
05962       struct sla_event *event;
05963       struct timespec ts = { 0, };
05964       unsigned int have_timeout = 0;
05965 
05966       if (AST_LIST_EMPTY(&sla.event_q)) {
05967          if ((have_timeout = sla_process_timers(&ts)))
05968             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
05969          else
05970             ast_cond_wait(&sla.cond, &sla.lock);
05971          if (sla.stop)
05972             break;
05973       }
05974 
05975       if (have_timeout)
05976          sla_process_timers(NULL);
05977 
05978       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
05979          ast_mutex_unlock(&sla.lock);
05980          switch (event->type) {
05981          case SLA_EVENT_HOLD:
05982             sla_handle_hold_event(event);
05983             break;
05984          case SLA_EVENT_DIAL_STATE:
05985             sla_handle_dial_state_event();
05986             break;
05987          case SLA_EVENT_RINGING_TRUNK:
05988             sla_handle_ringing_trunk_event();
05989             break;
05990          case SLA_EVENT_RELOAD:
05991             sla.reload = 1;
05992          case SLA_EVENT_CHECK_RELOAD:
05993             break;
05994          }
05995          ast_free(event);
05996          ast_mutex_lock(&sla.lock);
05997       }
05998 
05999       if (sla.reload) {
06000          sla_check_reload();
06001       }
06002    }
06003 
06004    ast_mutex_unlock(&sla.lock);
06005 
06006    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
06007       ast_free(ringing_station);
06008 
06009    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
06010       ast_free(failed_station);
06011 
06012    return NULL;
06013 }

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

Definition at line 6355 of file app_meetme.c.

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

Referenced by load_module().

06356 {
06357    char conf_name[MAX_CONFNUM];
06358    struct ast_conference *conf;
06359    struct ast_flags64 conf_flags = { 0 };
06360    struct sla_trunk *trunk;
06361    struct sla_ringing_trunk *ringing_trunk;
06362    AST_DECLARE_APP_ARGS(args,
06363       AST_APP_ARG(trunk_name);
06364       AST_APP_ARG(options);
06365    );
06366    char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
06367    struct ast_flags opt_flags = { 0 };
06368    char *parse;
06369 
06370    if (ast_strlen_zero(data)) {
06371       ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
06372       return -1;
06373    }
06374 
06375    parse = ast_strdupa(data);
06376    AST_STANDARD_APP_ARGS(args, parse);
06377    if (args.argc == 2) {
06378       if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
06379          ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
06380          return -1;
06381       }
06382    }
06383 
06384    AST_RWLIST_RDLOCK(&sla_trunks);
06385    trunk = sla_find_trunk(args.trunk_name);
06386    if (trunk)
06387       ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
06388    AST_RWLIST_UNLOCK(&sla_trunks);
06389 
06390    if (!trunk) {
06391       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
06392       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06393       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06394       return 0;
06395    }
06396 
06397    if (trunk->chan) {
06398       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
06399          args.trunk_name);
06400       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06401       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06402       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06403       return 0;
06404    }
06405 
06406    trunk->chan = chan;
06407 
06408    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
06409       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06410       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06411       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06412       return 0;
06413    }
06414 
06415    snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
06416    conf = build_conf(conf_name, "", "", 1, 1, 1, chan, NULL);
06417    if (!conf) {
06418       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
06419       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06420       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06421       return 0;
06422    }
06423    ast_set_flag64(&conf_flags, 
06424       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
06425 
06426    if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
06427       ast_indicate(chan, -1);
06428       ast_set_flag64(&conf_flags, CONFFLAG_MOH);
06429    } else
06430       ast_indicate(chan, AST_CONTROL_RINGING);
06431 
06432    conf_run(chan, conf, &conf_flags, opts);
06433    dispose_conf(conf);
06434    conf = NULL;
06435    trunk->chan = NULL;
06436    trunk->on_hold = 0;
06437 
06438    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
06439 
06440    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
06441       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
06442 
06443    /* Remove the entry from the list of ringing trunks if it is still there. */
06444    ast_mutex_lock(&sla.lock);
06445    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
06446       if (ringing_trunk->trunk == trunk) {
06447          AST_LIST_REMOVE_CURRENT(entry);
06448          break;
06449       }
06450    }
06451    AST_LIST_TRAVERSE_SAFE_END;
06452    ast_mutex_unlock(&sla.lock);
06453    if (ringing_trunk) {
06454       ast_free(ringing_trunk);
06455       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
06456       /* Queue reprocessing of ringing trunks to make stations stop ringing
06457        * that shouldn't be ringing after this trunk stopped. */
06458       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
06459    }
06460 
06461    ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
06462    sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
06463 
06464    return 0;
06465 }

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

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

01676 {
01677 #define S(e) case e: return # e;
01678    switch (state) {
01679    S(SLA_TRUNK_STATE_IDLE)
01680    S(SLA_TRUNK_STATE_RINGING)
01681    S(SLA_TRUNK_STATE_UP)
01682    S(SLA_TRUNK_STATE_ONHOLD)
01683    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01684    }
01685    return "Uknown State";
01686 #undef S
01687 }

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

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

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

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

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

01079 {
01080    tweak_volume(&user->talk, action);
01081    /* attempt to make the adjustment in the channel driver;
01082       if successful, don't adjust in the frame reading routine
01083    */
01084    if (!set_talk_volume(user, user->talk.desired))
01085       user->talk.actual = 0;
01086    else
01087       user->talk.actual = user->talk.desired;
01088 }

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

Definition at line 1043 of file app_meetme.c.

References volume::desired, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

01044 {
01045    switch (action) {
01046    case VOL_UP:
01047       switch (vol->desired) { 
01048       case 5:
01049          break;
01050       case 0:
01051          vol->desired = 2;
01052          break;
01053       case -2:
01054          vol->desired = 0;
01055          break;
01056       default:
01057          vol->desired++;
01058          break;
01059       }
01060       break;
01061    case VOL_DOWN:
01062       switch (vol->desired) {
01063       case -5:
01064          break;
01065       case 2:
01066          vol->desired = 0;
01067          break;
01068       case 0:
01069          vol->desired = -2;
01070          break;
01071       default:
01072          vol->desired--;
01073          break;
01074       }
01075    }
01076 }

static int unload_module ( void   )  [static]

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

07164 {
07165    int res = 0;
07166    
07167    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
07168    res = ast_manager_unregister("MeetmeMute");
07169    res |= ast_manager_unregister("MeetmeUnmute");
07170    res |= ast_manager_unregister("MeetmeList");
07171    res |= ast_unregister_application(app4);
07172    res |= ast_unregister_application(app3);
07173    res |= ast_unregister_application(app2);
07174    res |= ast_unregister_application(app);
07175    res |= ast_unregister_application(slastation_app);
07176    res |= ast_unregister_application(slatrunk_app);
07177 
07178 #ifdef TEST_FRAMEWORK
07179    AST_TEST_UNREGISTER(test_meetme_data_provider);
07180 #endif
07181    ast_data_unregister(NULL);
07182 
07183    ast_devstate_prov_del("Meetme");
07184    ast_devstate_prov_del("SLA");
07185    
07186    sla_destroy();
07187    
07188    res |= ast_custom_function_unregister(&meetme_info_acf);
07189    ast_unload_realtime("meetme");
07190 
07191    return res;
07192 }

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

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

07015 {
07016    struct ast_data *data_meetme_user;
07017    struct ast_data *data_meetme_user_channel;
07018    struct ast_data *data_meetme_user_volume;
07019 
07020    struct ast_conf_user *user = obj;
07021    struct ast_data *data_meetme_users = arg;
07022 
07023    data_meetme_user = ast_data_add_node(data_meetme_users, "user");
07024    if (!data_meetme_user) {
07025       return 0;
07026    }
07027    /* user structure */
07028    ast_data_add_structure(ast_conf_user, data_meetme_user, user);
07029 
07030    /* user's channel */
07031    data_meetme_user_channel = ast_data_add_node(data_meetme_user, "channel");
07032    if (!data_meetme_user_channel) {
07033       return 0;
07034    }
07035 
07036    ast_channel_data_add_structure(data_meetme_user_channel, user->chan, 1);
07037 
07038    /* volume structure */
07039    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "listen-volume");
07040    if (!data_meetme_user_volume) {
07041       return 0;
07042    }
07043    ast_data_add_int(data_meetme_user_volume, "desired", user->listen.desired);
07044    ast_data_add_int(data_meetme_user_volume, "actual", user->listen.actual);
07045 
07046    data_meetme_user_volume = ast_data_add_node(data_meetme_user, "talk-volume");
07047    if (!data_meetme_user_volume) {
07048       return 0;
07049    }
07050    ast_data_add_int(data_meetme_user_volume, "desired", user->talk.desired);
07051    ast_data_add_int(data_meetme_user_volume, "actual", user->talk.actual);
07052 
07053    return 0;
07054 }

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

Definition at line 4510 of file app_meetme.c.

References CMP_MATCH, CMP_STOP, and user.

Referenced by channel_admin_exec().

04511 {
04512    struct ast_conf_user *user = obj;
04513    const char *channel = args;
04514 
04515    if (!strcmp(user->chan->name, channel)) {
04516       return (CMP_MATCH | CMP_STOP);
04517    }
04518 
04519    return 0;
04520 }

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

Definition at line 4482 of file app_meetme.c.

References tweak_listen_volume(), and user.

Referenced by admin_exec().

04483 {
04484    struct ast_conf_user *user = obj;
04485    tweak_listen_volume(user, VOL_DOWN);
04486    return 0;
04487 }

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

Definition at line 4475 of file app_meetme.c.

References tweak_listen_volume(), user, and VOL_UP.

Referenced by admin_exec().

04476 {
04477    struct ast_conf_user *user = obj;
04478    tweak_listen_volume(user, VOL_UP);
04479    return 0;
04480 }

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

Definition at line 1156 of file app_meetme.c.

References user.

Referenced by admin_exec(), and conf_run().

01157 {
01158    struct ast_conf_user *user = obj;
01159    int *max_no = arg;
01160 
01161    if (user->user_no > *max_no) {
01162       *max_no = user->user_no;
01163    }
01164 
01165    return 0;
01166 }

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

Definition at line 1144 of file app_meetme.c.

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

Referenced by build_conf().

01145 {
01146    struct ast_conf_user *user = obj;
01147    int *user_no = arg;
01148 
01149    if (user->user_no == *user_no) {
01150       return (CMP_MATCH | CMP_STOP);
01151    }
01152 
01153    return 0;
01154 }

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

Definition at line 4503 of file app_meetme.c.

References reset_volumes(), and user.

Referenced by admin_exec().

04504 {
04505    struct ast_conf_user *user = obj;
04506    reset_volumes(user);
04507    return 0;
04508 }

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

Definition at line 2164 of file app_meetme.c.

References ADMINFLAG_KICKME, ast_test_flag64, CONFFLAG_ADMIN, and user.

Referenced by admin_exec(), and conf_run().

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

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

Definition at line 2186 of file app_meetme.c.

References ADMINFLAG_MUTED, ast_test_flag64, CONFFLAG_ADMIN, and user.

Referenced by admin_exec(), and conf_run().

02187 {
02188    struct ast_conf_user *user = obj;
02189    /* actual pointer contents of check_admin_arg is irrelevant */
02190 
02191    if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
02192       user->adminflags |= ADMINFLAG_MUTED;
02193    }
02194    return 0;
02195 }

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

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

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

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

Definition at line 4496 of file app_meetme.c.

References tweak_talk_volume(), and user.

Referenced by admin_exec().

04497 {
04498    struct ast_conf_user *user = obj;
04499    tweak_talk_volume(user, VOL_DOWN);
04500    return 0;
04501 }

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

Definition at line 4489 of file app_meetme.c.

References tweak_talk_volume(), user, and VOL_UP.

Referenced by admin_exec().

04490 {
04491    struct ast_conf_user *user = obj;
04492    tweak_talk_volume(user, VOL_UP);
04493    return 0;
04494 }


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

Definition at line 7238 of file app_meetme.c.

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

Definition at line 663 of file app_meetme.c.

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

Definition at line 664 of file app_meetme.c.

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

Definition at line 665 of file app_meetme.c.

Referenced by load_module(), and unload_module().

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

Definition at line 666 of file app_meetme.c.

Referenced by load_module(), and unload_module().

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 7238 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 946 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 955 of file app_meetme.c.

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1765 of file app_meetme.c.

Referenced by load_module(), and unload_module().

ast_cond_t cond

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

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

int earlyalert [static]

Definition at line 673 of file app_meetme.c.

int endalert [static]

Definition at line 674 of file app_meetme.c.

struct { ... } event_q

int extendby [static]

Definition at line 675 of file app_meetme.c.

struct { ... } failed_stations

struct sla_event* first

Definition at line 942 of file app_meetme.c.

struct sla_failed_station* first

Definition at line 941 of file app_meetme.c.

struct sla_ringing_station* first

Definition at line 940 of file app_meetme.c.

struct sla_ringing_trunk* first

Definition at line 939 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(), get_pattern_node(), 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 672 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 964 of file app_meetme.c.

struct sla_event* last

Definition at line 942 of file app_meetme.c.

struct sla_failed_station* last

Definition at line 941 of file app_meetme.c.

struct sla_ringing_station* last

Definition at line 940 of file app_meetme.c.

struct sla_ringing_trunk* last

Definition at line 939 of file app_meetme.c.

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

ast_mutex_t lock

Definition at line 938 of file app_meetme.c.

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

struct ast_data_handler meetme_data_provider [static]

Initial value:

Definition at line 7094 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 7099 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 6965 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 = (1ULL << 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 661 of file app_meetme.c.

Referenced by conf_exec().

static int reload

A reload has been requested

Definition at line 948 of file app_meetme.c.

Referenced by handle_cli_moh_reload(), and handle_minivm_reload().

struct { ... } ringing_stations

struct { ... } ringing_trunks

int rt_log_members [static]

Log participant count to the RealTime backend

Definition at line 678 of file app_meetme.c.

int rt_schedule [static]

Definition at line 671 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 878 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 6353 of file app_meetme.c.

Referenced by sla_trunk_exec().

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

Definition at line 667 of file app_meetme.c.

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

Definition at line 668 of file app_meetme.c.

unsigned int stop

Definition at line 943 of file app_meetme.c.

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

pthread_t thread

The SLA thread ID

Definition at line 936 of file app_meetme.c.

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


Generated on Mon Oct 8 12:39:07 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7