Tue Mar 2 17:32:12 2010

Asterisk developer's documentation


app_meetme.c File Reference

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

#include "asterisk.h"
#include <dahdi/user.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/astobj2.h"
#include "asterisk/devicestate.h"
#include "asterisk/dial.h"
#include "asterisk/causes.h"
#include "asterisk/paths.h"
#include "enter.h"
#include "leave.h"
Include dependency graph for app_meetme.c:

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

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

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int acf_meetme_info (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_meetme_info_eval (char *keyword, struct ast_conference *conf)
static int action_meetmelist (struct mansession *s, const struct message *m)
static int action_meetmemute (struct mansession *s, const struct message *m)
static int action_meetmeunmute (struct mansession *s, const struct message *m)
static int admin_exec (struct ast_channel *chan, void *data)
 The MeetMeadmin application.
static void * announce_thread (void *data)
static void answer_trunk_chan (struct ast_channel *chan)
static struct ast_conferencebuild_conf (char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan)
 Find or create a conference.
static int can_write (struct ast_channel *chan, int confflags)
static int careful_write (int fd, unsigned char *data, int len, int block)
static int channel_admin_exec (struct ast_channel *chan, void *data)
static char * complete_meetmecmd (const char *line, const char *word, int pos, int state)
static int conf_exec (struct ast_channel *chan, void *data)
 The meetme() application.
static void conf_flush (int fd, struct ast_channel *chan)
static int conf_free (struct ast_conference *conf)
static void conf_play (struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
static void conf_queue_dtmf (const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
static int conf_run (struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
static void conf_start_moh (struct ast_channel *chan, const char *musicclass)
static int count_exec (struct ast_channel *chan, void *data)
 The MeetmeCount application.
static struct sla_trunk_refcreate_trunk_ref (struct sla_trunk *trunk)
static void destroy_station (struct sla_station *station)
static void destroy_trunk (struct sla_trunk *trunk)
static void * dial_trunk (void *data)
static int dispose_conf (struct ast_conference *conf)
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
static struct ast_conferencefind_conf_realtime (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags, char *optargs[], int *too_early)
static struct ast_conf_userfind_user (struct ast_conference *conf, char *callerident)
static const char * get_announce_filename (enum announcetypes type)
static char * istalking (int x)
static int load_config (int reload)
static void load_config_meetme (void)
static int load_module (void)
static char * meetme_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static 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 void * run_station (void *data)
static void send_talking_event (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
static int set_listen_volume (struct ast_conf_user *user, int volume)
static int set_talk_volume (struct ast_conf_user *user, int volume)
static void set_user_talking (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
static void sla_add_trunk_to_station (struct sla_station *station, struct ast_variable *var)
static int sla_build_station (struct ast_config *cfg, const char *cat)
static int sla_build_trunk (struct ast_config *cfg, const char *cat)
static int sla_calc_station_delays (unsigned int *timeout)
 Calculate the ring delay for a station.
static int sla_calc_station_timeouts (unsigned int *timeout)
 Process station ring timeouts.
static int sla_calc_trunk_timeouts (unsigned int *timeout)
 Process trunk ring timeouts.
static void sla_change_trunk_state (const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
static int sla_check_device (const char *device)
static int sla_check_failed_station (const struct sla_station *station)
 Check to see if this station has failed to be dialed in the past minute.
static int sla_check_inuse_station (const struct sla_station *station)
 Check to see if a station is in use.
static void sla_check_reload (void)
 Check if we can do a reload of SLA, and do it if we can.
static int sla_check_ringing_station (const struct sla_station *station)
 Check to see if this station is already ringing.
static int sla_check_station_delay (struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
 Calculate the ring delay for a given ringing trunk on a station.
static int sla_check_station_hold_access (const struct sla_trunk *trunk, const struct sla_station *station)
static int sla_check_timed_out_station (const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
 Check to see if dialing this station already timed out for this ringing trunk.
static struct sla_trunk_refsla_choose_idle_trunk (const struct sla_station *station)
 For a given station, choose the highest priority idle trunk.
static struct sla_ringing_trunksla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int rm)
 Choose the highest priority ringing trunk for a station.
static struct sla_ringing_stationsla_create_ringing_station (struct sla_station *station)
static struct sla_station_refsla_create_station_ref (struct sla_station *station)
static void sla_destroy (void)
static void sla_dial_state_callback (struct ast_dial *dial)
static struct sla_stationsla_find_station (const char *name)
 Find an SLA station by name.
static struct sla_trunksla_find_trunk (const char *name)
 Find an SLA trunk by name.
static struct sla_trunk_refsla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk)
static struct sla_trunk_refsla_find_trunk_ref_byname (const struct sla_station *station, const char *name)
 Find a trunk reference on a station by name.
static void sla_handle_dial_state_event (void)
static void sla_handle_hold_event (struct sla_event *event)
static void sla_handle_ringing_trunk_event (void)
static void sla_hangup_stations (void)
static const char * sla_hold_str (unsigned int hold_access)
static int sla_load_config (int reload)
static int sla_process_timers (struct timespec *ts)
 Calculate the time until the next known event.
static void sla_queue_event (enum sla_event_type type)
static void sla_queue_event_conf (enum sla_event_type type, struct ast_channel *chan, struct ast_conference *conf)
 Queue a SLA event from the conference.
static void sla_queue_event_full (enum sla_event_type type, struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
static void sla_queue_event_nolock (enum sla_event_type type)
static int sla_ring_station (struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
 Ring a station.
static void sla_ring_stations (void)
 Ring stations based on current set of ringing trunks.
static char * sla_show_stations (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * sla_show_trunks (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static enum ast_device_state sla_state (const char *data)
static enum ast_device_state sla_state_to_devstate (enum sla_trunk_state state)
static int sla_station_exec (struct ast_channel *chan, void *data)
static void sla_stop_ringing_station (struct sla_ringing_station *ringing_station, enum sla_station_hangup hangup)
static void sla_stop_ringing_trunk (struct sla_ringing_trunk *ringing_trunk)
static void * sla_thread (void *data)
static int sla_trunk_exec (struct ast_channel *chan, void *data)
static const char * trunkstate2str (enum sla_trunk_state state)
static void tweak_listen_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_talk_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_volume (struct volume *vol, enum volume_action action)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, }
static const char * app = "MeetMe"
static const char * app2 = "MeetMeCount"
static const char * app3 = "MeetMeAdmin"
static const char * app4 = "MeetMeChannelAdmin"
static struct ast_module_infoast_module_info = &__mod_info
static int audio_buffers
static struct ast_cli_entry cli_meetme []
static unsigned int conf_map [1024] = {0, }
static const char * descrip
static const char * descrip2
static const char * descrip3
static const char * descrip4
static int earlyalert
static int endalert
static int fuzzystart
static char const gain_map []
static char mandescr_meetmelist []
static struct ast_custom_function meetme_info_acf
static struct ast_app_option meetme_opts [128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
static int rt_log_members
static int rt_schedule
struct {
   unsigned int   attempt_callerid:1
   ast_cond_t   cond
   struct {
      struct sla_event *   first
      struct sla_event *   last
   }   event_q
   struct {
      struct sla_failed_station *   first
      struct sla_failed_station *   last
   }   failed_stations
   ast_mutex_t   lock
   unsigned int   reload:1
   struct {
      struct sla_ringing_station *   first
      struct sla_ringing_station *   last
   }   ringing_stations
   struct {
      struct sla_ringing_trunk *   first
      struct sla_ringing_trunk *   last
   }   ringing_trunks
   unsigned int   stop:1
   pthread_t   thread
sla
 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 * slastation_app = "SLAStation"
static const char * slastation_desc
static const char * slastation_synopsis = "Shared Line Appearance Station"
static const char * slatrunk_app = "SLATrunk"
static const char * slatrunk_desc
static const char * slatrunk_synopsis = "Shared Line Appearance Trunk"
static const char * synopsis = "MeetMe conference bridge"
static const char * synopsis2 = "MeetMe participant count"
static const char * synopsis3 = "MeetMe conference Administration"
static const char * synopsis4 = "MeetMe conference Administration (channel specific)"

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

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

#define CONF_SIZE   320

Definition at line 105 of file app_meetme.c.

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 66 of file app_meetme.c.

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

String format for scheduled conferences

Definition at line 73 of file app_meetme.c.

Referenced by append_date(), build_radius_record(), execute_cb(), find_conf_realtime(), get_date(), manager_log(), pgsql_log(), and sqlite_log().

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 70 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

Definition at line 359 of file app_meetme.c.

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

#define MAX_PIN   80

Definition at line 360 of file app_meetme.c.

Referenced by conf_exec().

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

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

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

Referenced by meetme_cmd().

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 84 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 83 of file app_meetme.c.

Referenced by conf_run().

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

Referenced by sms_readfile(), and trunkstate2str().

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 67 of file app_meetme.c.

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


Enumeration Type Documentation

anonymous enum
Enumerator:
ADMINFLAG_MUTED 

User is muted

ADMINFLAG_SELFMUTED 

User muted self

ADMINFLAG_KICKME 

User has been kicked

ADMINFLAG_T_REQUEST 

User has requested to speak

Definition at line 75 of file app_meetme.c.

00075      {
00076    ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
00077    ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
00078    ADMINFLAG_KICKME =    (1 << 3),  /*!< User has been kicked */
00079    /*! User has requested to speak */
00080    ADMINFLAG_T_REQUEST = (1 << 4),
00081 };

anonymous enum
Enumerator:
CONFFLAG_ADMIN 

user has admin access on the conference

CONFFLAG_MONITOR 

If set the user can only receive audio from the conference

CONFFLAG_KEYEXIT 

If set asterisk will exit conference when key defined in p() option is pressed

CONFFLAG_STARMENU 

If set asterisk will provide a menu to the user when '*' is pressed

CONFFLAG_TALKER 

If set the use can only send audio to the conference

CONFFLAG_QUIET 

If set there will be no enter or leave sounds

CONFFLAG_ANNOUNCEUSERCOUNT 

If set, when user joins the conference, they will be told the number of users that are already in

CONFFLAG_AGI 

Set to run AGI Script in Background

CONFFLAG_MOH 

Set to have music on hold when user is alone in conference

CONFFLAG_MARKEDEXIT 

If set the MeetMe will return if all marked with this flag left

CONFFLAG_WAITMARKED 

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

CONFFLAG_EXIT_CONTEXT 

If set, the MeetMe will exit to the specified context

CONFFLAG_MARKEDUSER 

If set, the user will be marked

CONFFLAG_INTROUSER 

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

CONFFLAG_RECORDCONF 

If set, the MeetMe will be recorded

CONFFLAG_MONITORTALKER 

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

CONFFLAG_DYNAMIC 
CONFFLAG_DYNAMICPIN 
CONFFLAG_EMPTY 
CONFFLAG_EMPTYNOPIN 
CONFFLAG_ALWAYSPROMPT 
CONFFLAG_OPTIMIZETALKER 

If set, treat talking users as muted users

CONFFLAG_NOONLYPERSON 

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

CONFFLAG_INTROUSERNOREVIEW 

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

CONFFLAG_STARTMUTED 

If set, the user will be initially self-muted

CONFFLAG_PASS_DTMF 

Pass DTMF through the conference

CONFFLAG_SLA_STATION 
CONFFLAG_SLA_TRUNK 
CONFFLAG_KICK_CONTINUE 

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

CONFFLAG_DURATION_STOP 
CONFFLAG_DURATION_LIMIT 
CONFFLAG_NO_AUDIO_UNTIL_UP 

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

Definition at line 107 of file app_meetme.c.

00107      {
00108    /*! user has admin access on the conference */
00109    CONFFLAG_ADMIN = (1 << 0),
00110    /*! If set the user can only receive audio from the conference */
00111    CONFFLAG_MONITOR = (1 << 1),
00112    /*! If set asterisk will exit conference when key defined in p() option is pressed */
00113    CONFFLAG_KEYEXIT = (1 << 2),
00114    /*! If set asterisk will provide a menu to the user when '*' is pressed */
00115    CONFFLAG_STARMENU = (1 << 3),
00116    /*! If set the use can only send audio to the conference */
00117    CONFFLAG_TALKER = (1 << 4),
00118    /*! If set there will be no enter or leave sounds */
00119    CONFFLAG_QUIET = (1 << 5),
00120    /*! If set, when user joins the conference, they will be told the number 
00121     *  of users that are already in */
00122    CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
00123    /*! Set to run AGI Script in Background */
00124    CONFFLAG_AGI = (1 << 7),
00125    /*! Set to have music on hold when user is alone in conference */
00126    CONFFLAG_MOH = (1 << 8),
00127    /*! If set the MeetMe will return if all marked with this flag left */
00128    CONFFLAG_MARKEDEXIT = (1 << 9),
00129    /*! If set, the MeetMe will wait until a marked user enters */
00130    CONFFLAG_WAITMARKED = (1 << 10),
00131    /*! If set, the MeetMe will exit to the specified context */
00132    CONFFLAG_EXIT_CONTEXT = (1 << 11),
00133    /*! If set, the user will be marked */
00134    CONFFLAG_MARKEDUSER = (1 << 12),
00135    /*! If set, user will be ask record name on entry of conference */
00136    CONFFLAG_INTROUSER = (1 << 13),
00137    /*! If set, the MeetMe will be recorded */
00138    CONFFLAG_RECORDCONF = (1<< 14),
00139    /*! If set, the user will be monitored if the user is talking or not */
00140    CONFFLAG_MONITORTALKER = (1 << 15),
00141    CONFFLAG_DYNAMIC = (1 << 16),
00142    CONFFLAG_DYNAMICPIN = (1 << 17),
00143    CONFFLAG_EMPTY = (1 << 18),
00144    CONFFLAG_EMPTYNOPIN = (1 << 19),
00145    CONFFLAG_ALWAYSPROMPT = (1 << 20),
00146    /*! If set, treat talking users as muted users */
00147    CONFFLAG_OPTIMIZETALKER = (1 << 21),
00148    /*! If set, won't speak the extra prompt when the first person 
00149     *  enters the conference */
00150    CONFFLAG_NOONLYPERSON = (1 << 22),
00151    /*! If set, user will be asked to record name on entry of conference 
00152     *  without review */
00153    CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
00154    /*! If set, the user will be initially self-muted */
00155    CONFFLAG_STARTMUTED = (1 << 24),
00156    /*! Pass DTMF through the conference */
00157    CONFFLAG_PASS_DTMF = (1 << 25),
00158    CONFFLAG_SLA_STATION = (1 << 26),
00159    CONFFLAG_SLA_TRUNK = (1 << 27),
00160    /*! If set, the user should continue in the dialplan if kicked out */
00161    CONFFLAG_KICK_CONTINUE = (1 << 28),
00162    CONFFLAG_DURATION_STOP = (1 << 29),
00163    CONFFLAG_DURATION_LIMIT = (1 << 30),
00164    /*! Do not write any audio to this channel until the state is up. */
00165    CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31),
00166 };

anonymous enum
Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_EXITKEYS 
OPT_ARG_DURATION_STOP 
OPT_ARG_DURATION_LIMIT 
OPT_ARG_MOH_CLASS 
OPT_ARG_ARRAY_SIZE 

Definition at line 168 of file app_meetme.c.

00168      {
00169    OPT_ARG_WAITMARKED = 0,
00170    OPT_ARG_EXITKEYS   = 1,
00171    OPT_ARG_DURATION_STOP = 2,
00172    OPT_ARG_DURATION_LIMIT = 3,
00173    OPT_ARG_MOH_CLASS = 4,
00174    OPT_ARG_ARRAY_SIZE = 5,
00175 };

anonymous enum
Enumerator:
SLA_TRUNK_OPT_MOH 

Definition at line 5250 of file app_meetme.c.

05250      {
05251    SLA_TRUNK_OPT_MOH = (1 << 0),
05252 };

anonymous enum
Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 5254 of file app_meetme.c.

05254      {
05255    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
05256    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
05257 };

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 365 of file app_meetme.c.

00365                    {
00366    CONF_HASJOIN,
00367    CONF_HASLEFT
00368 };

Enumerator:
ENTER 
LEAVE 

Definition at line 93 of file app_meetme.c.

00093                     {
00094    ENTER,
00095    LEAVE
00096 };

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 98 of file app_meetme.c.

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

Enumerator:
SLA_EVENT_HOLD 

A station has put the call on hold

SLA_EVENT_DIAL_STATE 

The state of a dial has changed

SLA_EVENT_RINGING_TRUNK 

The state of a ringing trunk has changed

SLA_EVENT_RELOAD 

A reload of configuration has been requested

SLA_EVENT_CHECK_RELOAD 

Poke the SLA thread so it can check if it can perform a reload

Definition at line 555 of file app_meetme.c.

00555                     {
00556    /*! A station has put the call on hold */
00557    SLA_EVENT_HOLD,
00558    /*! The state of a dial has changed */
00559    SLA_EVENT_DIAL_STATE,
00560    /*! The state of a ringing trunk has changed */
00561    SLA_EVENT_RINGING_TRUNK,
00562    /*! A reload of configuration has been requested */
00563    SLA_EVENT_RELOAD,
00564    /*! Poke the SLA thread so it can check if it can perform a reload */
00565    SLA_EVENT_CHECK_RELOAD,
00566 };

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

00465                      {
00466    /*! This means that any station can put it on hold, and any station
00467     * can retrieve the call from hold. */
00468    SLA_HOLD_OPEN,
00469    /*! This means that only the station that put the call on hold may
00470     * retrieve it from hold. */
00471    SLA_HOLD_PRIVATE,
00472 };

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 592 of file app_meetme.c.

Enumerator:
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 457 of file app_meetme.c.

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 452 of file app_meetme.c.

00452                           {
00453    ALL_TRUNK_REFS,
00454    INACTIVE_TRUNK_REFS,
00455 };

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 88 of file app_meetme.c.

00088                    {
00089    VOL_UP,
00090    VOL_DOWN
00091 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 5953 of file app_meetme.c.

static void __unreg_module ( void   )  [static]

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

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

05807 {
05808    struct ast_conference *conf;
05809    char *parse;
05810    int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
05811    AST_DECLARE_APP_ARGS(args,
05812       AST_APP_ARG(keyword);
05813       AST_APP_ARG(confno);
05814    );
05815 
05816    if (ast_strlen_zero(data)) {
05817       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
05818       return -1;
05819    }
05820 
05821    parse = ast_strdupa(data);
05822    AST_STANDARD_APP_ARGS(args, parse);
05823 
05824    if (ast_strlen_zero(args.keyword)) {
05825       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
05826       return -1;
05827    }
05828 
05829    if (ast_strlen_zero(args.confno)) {
05830       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
05831       return -1;
05832    }
05833 
05834    AST_LIST_LOCK(&confs);
05835    AST_LIST_TRAVERSE(&confs, conf, list) {
05836       if (!strcmp(args.confno, conf->confno)) {
05837          result = acf_meetme_info_eval(args.keyword, conf);
05838          break;
05839       }
05840    }
05841    AST_LIST_UNLOCK(&confs);
05842 
05843    if (result > -1) {
05844       snprintf(buf, len, "%d", result);
05845    } else if (result == -1) {
05846       ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
05847       snprintf(buf, len, "0");
05848    } else if (result == -2) {
05849       ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno); 
05850       snprintf(buf, len, "0");
05851    }
05852 
05853    return 0;
05854 }

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

Definition at line 5788 of file app_meetme.c.

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

Referenced by acf_meetme_info().

05789 {
05790    if (!strcasecmp("lock", keyword)) {
05791       return conf->locked;
05792    } else if (!strcasecmp("parties", keyword)) {
05793       return conf->users;
05794    } else if (!strcasecmp("activity", keyword)) {
05795       time_t now;
05796       now = time(NULL);
05797       return (now - conf->start);
05798    } else if (!strcasecmp("dynamic", keyword)) {
05799       return conf->isdynamic;
05800    } else {
05801       return -1;
05802    }
05803 
05804 }

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

Definition at line 3758 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_error(), astman_send_listack(), ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CONFFLAG_ADMIN, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_conference::confno, ast_conf_user::list, S_OR, ast_conf_user::talking, total, ast_conf_user::user_no, ast_conf_user::userflags, and ast_conference::userlist.

Referenced by load_module().

03759 {
03760    const char *actionid = astman_get_header(m, "ActionID");
03761    const char *conference = astman_get_header(m, "Conference");
03762    char idText[80] = "";
03763    struct ast_conference *cnf;
03764    struct ast_conf_user *user;
03765    int total = 0;
03766 
03767    if (!ast_strlen_zero(actionid))
03768       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
03769 
03770    if (AST_LIST_EMPTY(&confs)) {
03771       astman_send_error(s, m, "No active conferences.");
03772       return 0;
03773    }
03774 
03775    astman_send_listack(s, m, "Meetme user list will follow", "start");
03776 
03777    /* Find the right conference */
03778    AST_LIST_LOCK(&confs);
03779    AST_LIST_TRAVERSE(&confs, cnf, list) {
03780       /* If we ask for one particular, and this isn't it, skip it */
03781       if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
03782          continue;
03783 
03784       /* Show all the users */
03785       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03786          total++;
03787          astman_append(s,
03788          "Event: MeetmeList\r\n"
03789          "%s"
03790          "Conference: %s\r\n"
03791          "UserNumber: %d\r\n"
03792          "CallerIDNum: %s\r\n"
03793          "CallerIDName: %s\r\n"
03794          "Channel: %s\r\n"
03795          "Admin: %s\r\n"
03796          "Role: %s\r\n"
03797          "MarkedUser: %s\r\n"
03798          "Muted: %s\r\n"
03799          "Talking: %s\r\n"
03800          "\r\n",
03801          idText,
03802          cnf->confno,
03803          user->user_no,
03804          S_OR(user->chan->cid.cid_num, "<unknown>"),
03805          S_OR(user->chan->cid.cid_name, "<no name>"),
03806          user->chan->name,
03807          user->userflags & CONFFLAG_ADMIN ? "Yes" : "No",
03808          user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen",
03809          user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No",
03810          user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
03811          user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored"); 
03812       }
03813    }
03814    AST_LIST_UNLOCK(&confs);
03815    /* Send final confirmation */
03816    astman_append(s,
03817    "Event: MeetmeListComplete\r\n"
03818    "EventList: Complete\r\n"
03819    "ListItems: %d\r\n"
03820    "%s"
03821    "\r\n", total, idText);
03822    return 0;
03823 }

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

Definition at line 3740 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

03741 {
03742    return meetmemute(s, m, 1);
03743 }

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

Definition at line 3745 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

03746 {
03747    return meetmemute(s, m, 0);
03748 }

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

The MeetMeadmin application.

Definition at line 3470 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, AST_APP_ARG, ast_atomic_fetchadd_int(), AST_DECLARE_APP_ARGS, AST_LIST_LAST, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), CONFFLAG_ADMIN, ast_conference::confno, dispose_conf(), find_user(), ast_conf_user::list, ast_conference::locked, LOG_NOTICE, LOG_WARNING, ast_conference::refcount, reset_volumes(), tweak_listen_volume(), tweak_talk_volume(), ast_conf_user::userflags, ast_conference::userlist, VOL_DOWN, and VOL_UP.

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

03470                                                             {
03471    char *params;
03472    struct ast_conference *cnf;
03473    struct ast_conf_user *user = NULL;
03474    AST_DECLARE_APP_ARGS(args,
03475       AST_APP_ARG(confno);
03476       AST_APP_ARG(command);
03477       AST_APP_ARG(user);
03478    );
03479 
03480    if (ast_strlen_zero(data)) {
03481       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
03482       return -1;
03483    }
03484 
03485    params = ast_strdupa(data);
03486    AST_STANDARD_APP_ARGS(args, params);
03487 
03488    if (!args.command) {
03489       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
03490       return -1;
03491    }
03492 
03493    AST_LIST_LOCK(&confs);
03494    AST_LIST_TRAVERSE(&confs, cnf, list) {
03495       if (!strcmp(cnf->confno, args.confno))
03496          break;
03497    }
03498 
03499    if (!cnf) {
03500       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
03501       AST_LIST_UNLOCK(&confs);
03502       return 0;
03503    }
03504 
03505    ast_atomic_fetchadd_int(&cnf->refcount, 1);
03506 
03507    if (args.user)
03508       user = find_user(cnf, args.user);
03509 
03510    switch (*args.command) {
03511    case 76: /* L: Lock */ 
03512       cnf->locked = 1;
03513       break;
03514    case 108: /* l: Unlock */ 
03515       cnf->locked = 0;
03516       break;
03517    case 75: /* K: kick all users */
03518       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03519          user->adminflags |= ADMINFLAG_KICKME;
03520       break;
03521    case 101: /* e: Eject last user*/
03522       user = AST_LIST_LAST(&cnf->userlist);
03523       if (!(user->userflags & CONFFLAG_ADMIN))
03524          user->adminflags |= ADMINFLAG_KICKME;
03525       else
03526          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
03527       break;
03528    case 77: /* M: Mute */ 
03529       if (user) {
03530          user->adminflags |= ADMINFLAG_MUTED;
03531       } else
03532          ast_log(LOG_NOTICE, "Specified User not found!\n");
03533       break;
03534    case 78: /* N: Mute all (non-admin) users */
03535       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03536          if (!(user->userflags & CONFFLAG_ADMIN))
03537             user->adminflags |= ADMINFLAG_MUTED;
03538       }
03539       break;               
03540    case 109: /* m: Unmute */ 
03541       if (user) {
03542          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03543       } else
03544          ast_log(LOG_NOTICE, "Specified User not found!\n");
03545       break;
03546    case 110: /* n: Unmute all users */
03547       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03548          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03549       break;
03550    case 107: /* k: Kick user */ 
03551       if (user)
03552          user->adminflags |= ADMINFLAG_KICKME;
03553       else
03554          ast_log(LOG_NOTICE, "Specified User not found!\n");
03555       break;
03556    case 118: /* v: Lower all users listen volume */
03557       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03558          tweak_listen_volume(user, VOL_DOWN);
03559       break;
03560    case 86: /* V: Raise all users listen volume */
03561       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03562          tweak_listen_volume(user, VOL_UP);
03563       break;
03564    case 115: /* s: Lower all users speaking volume */
03565       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03566          tweak_talk_volume(user, VOL_DOWN);
03567       break;
03568    case 83: /* S: Raise all users speaking volume */
03569       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03570          tweak_talk_volume(user, VOL_UP);
03571       break;
03572    case 82: /* R: Reset all volume levels */
03573       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03574          reset_volumes(user);
03575       break;
03576    case 114: /* r: Reset user's volume level */
03577       if (user)
03578          reset_volumes(user);
03579       else
03580          ast_log(LOG_NOTICE, "Specified User not found!\n");
03581       break;
03582    case 85: /* U: Raise user's listen volume */
03583       if (user)
03584          tweak_listen_volume(user, VOL_UP);
03585       else
03586          ast_log(LOG_NOTICE, "Specified User not found!\n");
03587       break;
03588    case 117: /* u: Lower user's listen volume */
03589       if (user)
03590          tweak_listen_volume(user, VOL_DOWN);
03591       else
03592          ast_log(LOG_NOTICE, "Specified User not found!\n");
03593       break;
03594    case 84: /* T: Raise user's talk volume */
03595       if (user)
03596          tweak_talk_volume(user, VOL_UP);
03597       else
03598          ast_log(LOG_NOTICE, "Specified User not found!\n");
03599       break;
03600    case 116: /* t: Lower user's talk volume */
03601       if (user) 
03602          tweak_talk_volume(user, VOL_DOWN);
03603       else 
03604          ast_log(LOG_NOTICE, "Specified User not found!\n");
03605       break;
03606    }
03607 
03608    AST_LIST_UNLOCK(&confs);
03609 
03610    dispose_conf(cnf);
03611    
03612    return 0;
03613 }

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

Definition at line 1573 of file app_meetme.c.

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

Referenced by conf_run().

01574 {
01575    struct announce_listitem *current;
01576    struct ast_conference *conf = data;
01577    int res = 0;
01578    char filename[PATH_MAX] = "";
01579    AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
01580    AST_LIST_HEAD_INIT_NOLOCK(&local_list);
01581 
01582    while (!conf->announcethread_stop) {
01583       ast_mutex_lock(&conf->announcelistlock);
01584       if (conf->announcethread_stop) {
01585          ast_mutex_unlock(&conf->announcelistlock);
01586          break;
01587       }
01588       if (AST_LIST_EMPTY(&conf->announcelist))
01589          ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
01590 
01591       AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
01592       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01593 
01594       ast_mutex_unlock(&conf->announcelistlock);
01595       if (conf->announcethread_stop) {
01596          break;
01597       }
01598 
01599       for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
01600          ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
01601          if (!ast_fileexists(current->namerecloc, NULL, NULL))
01602             continue;
01603          if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
01604             if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
01605                res = ast_waitstream(current->confchan, "");
01606             if (!res) {
01607                ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
01608                if (!ast_streamfile(current->confchan, filename, current->language))
01609                   ast_waitstream(current->confchan, "");
01610             }
01611          }
01612          if (current->announcetype == CONF_HASLEFT) {
01613             ast_filedelete(current->namerecloc, NULL);
01614          }
01615       }
01616    }
01617 
01618    /* thread marked to stop, clean up */
01619    while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
01620       ast_filedelete(current->namerecloc, NULL);
01621       ao2_ref(current, -1);
01622    }
01623    return NULL;
01624 }

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

Definition at line 4122 of file app_meetme.c.

References ast_answer(), and ast_indicate().

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

04123 {
04124    ast_answer(chan);
04125    ast_indicate(chan, -1);
04126 }

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

Find or create a conference.

Parameters:
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 831 of file app_meetme.c.

References ast_conference::announcethread, ast_conference::announcethreadlock, ast_atomic_fetchadd_int(), ast_calloc, ast_copy_string(), AST_FORMAT_SLINEAR, ast_free, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), AST_PTHREADT_NULL, ast_request(), ast_set_read_format(), ast_set_write_format(), ast_verb, ast_conference::chan, conf_map, ast_conference::confno, ast_conference::dahdiconf, ast_conference::fd, ast_channel::fds, ast_conference::isdynamic, ast_conference::listenlock, LOG_WARNING, ast_conference::maxusers, ast_conference::pin, ast_conference::pinadmin, ast_conference::playlock, ast_conference::recordthread, ast_conference::recordthreadlock, ast_conference::refcount, ast_conference::start, and ast_conference::uniqueid.

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

00832 {
00833    struct ast_conference *cnf;
00834    struct dahdi_confinfo dahdic = { 0, };
00835    int confno_int = 0;
00836 
00837    AST_LIST_LOCK(&confs);
00838 
00839    AST_LIST_TRAVERSE(&confs, cnf, list) {
00840       if (!strcmp(confno, cnf->confno)) 
00841          break;
00842    }
00843 
00844    if (cnf || (!make && !dynamic))
00845       goto cnfout;
00846 
00847    /* Make a new one */
00848    if (!(cnf = ast_calloc(1, sizeof(*cnf))))
00849       goto cnfout;
00850 
00851    ast_mutex_init(&cnf->playlock);
00852    ast_mutex_init(&cnf->listenlock);
00853    cnf->recordthread = AST_PTHREADT_NULL;
00854    ast_mutex_init(&cnf->recordthreadlock);
00855    cnf->announcethread = AST_PTHREADT_NULL;
00856    ast_mutex_init(&cnf->announcethreadlock);
00857    ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00858    ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00859    ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00860    ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid));
00861 
00862    /* Setup a new dahdi conference */
00863    dahdic.confno = -1;
00864    dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00865    cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
00866    if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
00867       ast_log(LOG_WARNING, "Unable to open pseudo device\n");
00868       if (cnf->fd >= 0)
00869          close(cnf->fd);
00870       ast_free(cnf);
00871       cnf = NULL;
00872       goto cnfout;
00873    }
00874 
00875    cnf->dahdiconf = dahdic.confno;
00876 
00877    /* Setup a new channel for playback of audio files */
00878    cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL);
00879    if (cnf->chan) {
00880       ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
00881       ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
00882       dahdic.chan = 0;
00883       dahdic.confno = cnf->dahdiconf;
00884       dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00885       if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
00886          ast_log(LOG_WARNING, "Error setting conference\n");
00887          if (cnf->chan)
00888             ast_hangup(cnf->chan);
00889          else
00890             close(cnf->fd);
00891 
00892          ast_free(cnf);
00893          cnf = NULL;
00894          goto cnfout;
00895       }
00896    }
00897 
00898    /* Fill the conference struct */
00899    cnf->start = time(NULL);
00900    cnf->maxusers = 0x7fffffff;
00901    cnf->isdynamic = dynamic ? 1 : 0;
00902    ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
00903    AST_LIST_INSERT_HEAD(&confs, cnf, list);
00904 
00905    /* Reserve conference number in map */
00906    if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
00907       conf_map[confno_int] = 1;
00908    
00909 cnfout:
00910    if (cnf)
00911       ast_atomic_fetchadd_int(&cnf->refcount, refcount);
00912 
00913    AST_LIST_UNLOCK(&confs);
00914 
00915    return cnf;
00916 }

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

Definition at line 1626 of file app_meetme.c.

References ast_channel::_state, AST_STATE_UP, and CONFFLAG_NO_AUDIO_UNTIL_UP.

Referenced by conf_run().

01627 {
01628    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01629       return 1;
01630    }
01631 
01632    return (chan->_state == AST_STATE_UP);
01633 }

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

Definition at line 665 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

Referenced by conf_play(), and conf_run().

00666 {
00667    int res;
00668    int x;
00669 
00670    while (len) {
00671       if (block) {
00672          x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
00673          res = ioctl(fd, DAHDI_IOMUX, &x);
00674       } else
00675          res = 0;
00676       if (res >= 0)
00677          res = write(fd, data, len);
00678       if (res < 1) {
00679          if (errno != EAGAIN) {
00680             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00681             return -1;
00682          } else
00683             return 0;
00684       }
00685       len -= res;
00686       data += res;
00687    }
00688 
00689    return 0;
00690 }

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

Definition at line 3617 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ast_conf_user::adminflags, 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::chan, ast_conf_user::list, LOG_NOTICE, LOG_WARNING, and ast_conference::userlist.

Referenced by load_module().

03617                                                                     {
03618    char *params;
03619    struct ast_conference *conf = NULL;
03620    struct ast_conf_user *user = NULL;
03621    AST_DECLARE_APP_ARGS(args,
03622       AST_APP_ARG(channel);
03623       AST_APP_ARG(command);
03624    );
03625 
03626    if (ast_strlen_zero(data)) {
03627       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
03628       return -1;
03629    }
03630    
03631    params = ast_strdupa(data);
03632    AST_STANDARD_APP_ARGS(args, params);
03633 
03634    if (!args.channel) {
03635       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
03636       return -1;
03637    }
03638 
03639    if (!args.command) {
03640       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
03641       return -1;
03642    }
03643 
03644    AST_LIST_LOCK(&confs);
03645    AST_LIST_TRAVERSE(&confs, conf, list) {
03646       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03647          if (!strcmp(user->chan->name, args.channel))
03648             break;
03649       }
03650    }
03651    
03652    if (!user) {
03653       ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
03654       AST_LIST_UNLOCK(&confs);
03655       return 0;
03656    }
03657    
03658    /* perform the specified action */
03659    switch (*args.command) {
03660       case 77: /* M: Mute */ 
03661          user->adminflags |= ADMINFLAG_MUTED;
03662          break;
03663       case 109: /* m: Unmute */ 
03664          user->adminflags &= ~ADMINFLAG_MUTED;
03665          break;
03666       case 107: /* k: Kick user */ 
03667          user->adminflags |= ADMINFLAG_KICKME;
03668          break;
03669       default: /* unknown command */
03670          ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
03671          break;
03672    }
03673 
03674    AST_LIST_UNLOCK(&confs);
03675    
03676    return 0;
03677 }

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

Definition at line 919 of file app_meetme.c.

References 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::userlist.

Referenced by meetme_cmd().

00920 {
00921    static char *cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
00922 
00923    int len = strlen(word);
00924    int which = 0;
00925    struct ast_conference *cnf = NULL;
00926    struct ast_conf_user *usr = NULL;
00927    char *confno = NULL;
00928    char usrno[50] = "";
00929    char *myline, *ret = NULL;
00930    
00931    if (pos == 1) {      /* Command */
00932       return ast_cli_complete(word, cmds, state);
00933    } else if (pos == 2) {  /* Conference Number */
00934       AST_LIST_LOCK(&confs);
00935       AST_LIST_TRAVERSE(&confs, cnf, list) {
00936          if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
00937             ret = cnf->confno;
00938             break;
00939          }
00940       }
00941       ret = ast_strdup(ret); /* dup before releasing the lock */
00942       AST_LIST_UNLOCK(&confs);
00943       return ret;
00944    } else if (pos == 3) {
00945       /* User Number || Conf Command option*/
00946       if (strstr(line, "mute") || strstr(line, "kick")) {
00947          if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
00948             return ast_strdup("all");
00949          which++;
00950          AST_LIST_LOCK(&confs);
00951 
00952          /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
00953          myline = ast_strdupa(line);
00954          if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
00955             while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
00956                ;
00957          }
00958          
00959          AST_LIST_TRAVERSE(&confs, cnf, list) {
00960             if (!strcmp(confno, cnf->confno))
00961                 break;
00962          }
00963 
00964          if (cnf) {
00965             /* Search for the user */
00966             AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
00967                snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
00968                if (!strncasecmp(word, usrno, len) && ++which > state)
00969                   break;
00970             }
00971          }
00972          AST_LIST_UNLOCK(&confs);
00973          return usr ? ast_strdup(usrno) : NULL;
00974       } else if (strstr(line, "list") && (state == 0))
00975          return ast_strdup("concise");
00976    }
00977 
00978    return NULL;
00979 }

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

The meetme() application.

Definition at line 3207 of file app_meetme.c.

References ast_channel::_state, ARRAY_LEN, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options(), 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_log(), ast_say_digits(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_variable_browse(), ast_waitstream(), conf_map, conf_run(), CONFFLAG_ADMIN, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFFLAG_QUIET, CONFIG_FILE_NAME, config_flags, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), ast_flags::flags, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, MAX_SETTINGS, meetme_opts, ast_variable::name, ast_variable::next, OPT_ARG_ARRAY_SIZE, parse(), ast_conference::pin, ast_conference::pinadmin, strsep(), ast_variable::value, and var.

Referenced by load_module().

03208 {
03209    int res = -1;
03210    char confno[MAX_CONFNUM] = "";
03211    int allowretry = 0;
03212    int retrycnt = 0;
03213    struct ast_conference *cnf = NULL;
03214    struct ast_flags confflags = {0}, config_flags = { 0 };
03215    int dynamic = 0;
03216    int empty = 0, empty_no_pin = 0;
03217    int always_prompt = 0;
03218    char *notdata, *info, the_pin[MAX_PIN] = "";
03219    AST_DECLARE_APP_ARGS(args,
03220       AST_APP_ARG(confno);
03221       AST_APP_ARG(options);
03222       AST_APP_ARG(pin);
03223    );
03224    char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
03225 
03226    if (ast_strlen_zero(data)) {
03227       allowretry = 1;
03228       notdata = "";
03229    } else {
03230       notdata = data;
03231    }
03232    
03233    if (chan->_state != AST_STATE_UP)
03234       ast_answer(chan);
03235 
03236    info = ast_strdupa(notdata);
03237 
03238    AST_STANDARD_APP_ARGS(args, info);  
03239 
03240    if (args.confno) {
03241       ast_copy_string(confno, args.confno, sizeof(confno));
03242       if (ast_strlen_zero(confno)) {
03243          allowretry = 1;
03244       }
03245    }
03246    
03247    if (args.pin)
03248       ast_copy_string(the_pin, args.pin, sizeof(the_pin));
03249 
03250    if (args.options) {
03251       ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
03252       dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
03253       if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
03254          strcpy(the_pin, "q");
03255 
03256       empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
03257       empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
03258       always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
03259    }
03260 
03261    do {
03262       if (retrycnt > 3)
03263          allowretry = 0;
03264       if (empty) {
03265          int i;
03266          struct ast_config *cfg;
03267          struct ast_variable *var;
03268          int confno_int;
03269 
03270          /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
03271          if ((empty_no_pin) || (!dynamic)) {
03272             cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03273             if (cfg) {
03274                var = ast_variable_browse(cfg, "rooms");
03275                while (var) {
03276                   char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
03277                   if (!strcasecmp(var->name, "conf")) {
03278                      int found = 0;
03279                      ast_copy_string(parse, var->value, sizeof(parse));
03280                      confno_tmp = strsep(&stringp, "|,");
03281                      if (!dynamic) {
03282                         /* For static:  run through the list and see if this conference is empty */
03283                         AST_LIST_LOCK(&confs);
03284                         AST_LIST_TRAVERSE(&confs, cnf, list) {
03285                            if (!strcmp(confno_tmp, cnf->confno)) {
03286                               /* The conference exists, therefore it's not empty */
03287                               found = 1;
03288                               break;
03289                            }
03290                         }
03291                         AST_LIST_UNLOCK(&confs);
03292                         if (!found) {
03293                            /* At this point, we have a confno_tmp (static conference) that is empty */
03294                            if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
03295                               /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
03296                                * Case 2:  empty_no_pin and pin is blank (but not NULL)
03297                                * Case 3:  not empty_no_pin
03298                                */
03299                               ast_copy_string(confno, confno_tmp, sizeof(confno));
03300                               break;
03301                               /* XXX the map is not complete (but we do have a confno) */
03302                            }
03303                         }
03304                      }
03305                   }
03306                   var = var->next;
03307                }
03308                ast_config_destroy(cfg);
03309             }
03310          }
03311 
03312          /* Select first conference number not in use */
03313          if (ast_strlen_zero(confno) && dynamic) {
03314             AST_LIST_LOCK(&confs);
03315             for (i = 0; i < ARRAY_LEN(conf_map); i++) {
03316                if (!conf_map[i]) {
03317                   snprintf(confno, sizeof(confno), "%d", i);
03318                   conf_map[i] = 1;
03319                   break;
03320                }
03321             }
03322             AST_LIST_UNLOCK(&confs);
03323          }
03324 
03325          /* Not found? */
03326          if (ast_strlen_zero(confno)) {
03327             res = ast_streamfile(chan, "conf-noempty", chan->language);
03328             if (!res)
03329                ast_waitstream(chan, "");
03330          } else {
03331             if (sscanf(confno, "%30d", &confno_int) == 1) {
03332                if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
03333                   res = ast_streamfile(chan, "conf-enteringno", chan->language);
03334                   if (!res) {
03335                      ast_waitstream(chan, "");
03336                      res = ast_say_digits(chan, confno_int, "", chan->language);
03337                   }
03338                }
03339             } else {
03340                ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
03341             }
03342          }
03343       }
03344 
03345       while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
03346          /* Prompt user for conference number */
03347          res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
03348          if (res < 0) {
03349             /* Don't try to validate when we catch an error */
03350             confno[0] = '\0';
03351             allowretry = 0;
03352             break;
03353          }
03354       }
03355       if (!ast_strlen_zero(confno)) {
03356          /* Check the validity of the conference */
03357          cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
03358             sizeof(the_pin), 1, &confflags);
03359          if (!cnf) {
03360             int too_early = 0;
03361             cnf = find_conf_realtime(chan, confno, 1, dynamic, 
03362                the_pin, sizeof(the_pin), 1, &confflags, optargs, &too_early);
03363             if (rt_schedule && too_early)
03364                allowretry = 0;
03365          }
03366 
03367          if (!cnf) {
03368             if (allowretry) {
03369                confno[0] = '\0';
03370                res = ast_streamfile(chan, "conf-invalid", chan->language);
03371                if (!res)
03372                   ast_waitstream(chan, "");
03373                res = -1;
03374             }
03375          } else {
03376             if ((!ast_strlen_zero(cnf->pin) &&
03377                  !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
03378                 (!ast_strlen_zero(cnf->pinadmin) &&
03379                  ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
03380                char pin[MAX_PIN] = "";
03381                int j;
03382 
03383                /* Allow the pin to be retried up to 3 times */
03384                for (j = 0; j < 3; j++) {
03385                   if (*the_pin && (always_prompt == 0)) {
03386                      ast_copy_string(pin, the_pin, sizeof(pin));
03387                      res = 0;
03388                   } else {
03389                      /* Prompt user for pin if pin is required */
03390                      res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
03391                   }
03392                   if (res >= 0) {
03393                      if (!strcasecmp(pin, cnf->pin) ||
03394                          (!ast_strlen_zero(cnf->pinadmin) &&
03395                           !strcasecmp(pin, cnf->pinadmin))) {
03396                         /* Pin correct */
03397                         allowretry = 0;
03398                         if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
03399                            ast_set_flag(&confflags, CONFFLAG_ADMIN);
03400                         /* Run the conference */
03401                         res = conf_run(chan, cnf, confflags.flags, optargs);
03402                         break;
03403                      } else {
03404                         /* Pin invalid */
03405                         if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
03406                            res = ast_waitstream(chan, AST_DIGIT_ANY);
03407                            ast_stopstream(chan);
03408                         }
03409                         else {
03410                            ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
03411                            break;
03412                         }
03413                         if (res < 0)
03414                            break;
03415                         pin[0] = res;
03416                         pin[1] = '\0';
03417                         res = -1;
03418                         if (allowretry)
03419                            confno[0] = '\0';
03420                      }
03421                   } else {
03422                      /* failed when getting the pin */
03423                      res = -1;
03424                      allowretry = 0;
03425                      /* see if we need to get rid of the conference */
03426                      break;
03427                   }
03428 
03429                   /* Don't retry pin with a static pin */
03430                   if (*the_pin && (always_prompt == 0)) {
03431                      break;
03432                   }
03433                }
03434             } else {
03435                /* No pin required */
03436                allowretry = 0;
03437 
03438                /* Run the conference */
03439                res = conf_run(chan, cnf, confflags.flags, optargs);
03440             }
03441             dispose_conf(cnf);
03442             cnf = NULL;
03443          }
03444       }
03445    } while (allowretry);
03446 
03447    if (cnf)
03448       dispose_conf(cnf);
03449    
03450    return res;
03451 }

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

Definition at line 1346 of file app_meetme.c.

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

Referenced by conf_run().

01347 {
01348    int x;
01349 
01350    /* read any frames that may be waiting on the channel
01351       and throw them away
01352    */
01353    if (chan) {
01354       struct ast_frame *f;
01355 
01356       /* when no frames are available, this will wait
01357          for 1 millisecond maximum
01358       */
01359       while (ast_waitfor(chan, 1)) {
01360          f = ast_read(chan);
01361          if (f)
01362             ast_frfree(f);
01363          else /* channel was hung up or something else happened */
01364             break;
01365       }
01366    }
01367 
01368    /* flush any data sitting in the pseudo channel */
01369    x = DAHDI_FLUSH_ALL;
01370    if (ioctl(fd, DAHDI_FLUSH, &x))
01371       ast_log(LOG_WARNING, "Error flushing channel\n");
01372 
01373 }

static int conf_free ( struct ast_conference conf  )  [static]

Definition at line 1377 of file app_meetme.c.

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

Referenced by dispose_conf().

01378 {
01379    int x;
01380    struct announce_listitem *item;
01381    
01382    AST_LIST_REMOVE(&confs, conf, list);
01383    manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01384 
01385    if (conf->recording == MEETME_RECORD_ACTIVE) {
01386       conf->recording = MEETME_RECORD_TERMINATE;
01387       AST_LIST_UNLOCK(&confs);
01388       while (1) {
01389          usleep(1);
01390          AST_LIST_LOCK(&confs);
01391          if (conf->recording == MEETME_RECORD_OFF)
01392             break;
01393          AST_LIST_UNLOCK(&confs);
01394       }
01395    }
01396 
01397    for (x = 0; x < AST_FRAME_BITS; x++) {
01398       if (conf->transframe[x])
01399          ast_frfree(conf->transframe[x]);
01400       if (conf->transpath[x])
01401          ast_translator_free_path(conf->transpath[x]);
01402    }
01403    if (conf->announcethread != AST_PTHREADT_NULL) {
01404       ast_mutex_lock(&conf->announcelistlock);
01405       conf->announcethread_stop = 1;
01406       ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01407       ast_cond_signal(&conf->announcelist_addition);
01408       ast_mutex_unlock(&conf->announcelistlock);
01409       pthread_join(conf->announcethread, NULL);
01410    
01411       while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01412          ast_filedelete(item->namerecloc, NULL);
01413          ao2_ref(item, -1);
01414       }
01415       ast_mutex_destroy(&conf->announcelistlock);
01416    }
01417    if (conf->origframe)
01418       ast_frfree(conf->origframe);
01419    if (conf->lchan)
01420       ast_hangup(conf->lchan);
01421    if (conf->chan)
01422       ast_hangup(conf->chan);
01423    if (conf->fd >= 0)
01424       close(conf->fd);
01425    if (conf->recordingfilename) {
01426       ast_free(conf->recordingfilename);
01427    }
01428    if (conf->recordingformat) {
01429       ast_free(conf->recordingformat);
01430    }
01431    ast_mutex_destroy(&conf->playlock);
01432    ast_mutex_destroy(&conf->listenlock);
01433    ast_mutex_destroy(&conf->recordthreadlock);
01434    ast_mutex_destroy(&conf->announcethreadlock);
01435    ast_free(conf);
01436 
01437    return 0;
01438 }

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

Definition at line 783 of file app_meetme.c.

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

Referenced by conf_run().

00784 {
00785    unsigned char *data;
00786    int len;
00787    int res = -1;
00788 
00789    if (!ast_check_hangup(chan))
00790       res = ast_autoservice_start(chan);
00791 
00792    AST_LIST_LOCK(&confs);
00793 
00794    switch(sound) {
00795    case ENTER:
00796       data = enter;
00797       len = sizeof(enter);
00798       break;
00799    case LEAVE:
00800       data = leave;
00801       len = sizeof(leave);
00802       break;
00803    default:
00804       data = NULL;
00805       len = 0;
00806    }
00807    if (data) {
00808       careful_write(conf->fd, data, len, 1);
00809    }
00810 
00811    AST_LIST_UNLOCK(&confs);
00812 
00813    if (!res) 
00814       ast_autoservice_stop(chan);
00815 }

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

Definition at line 1440 of file app_meetme.c.

References AST_LIST_TRAVERSE, ast_log(), ast_write(), ast_conf_user::chan, ast_conf_user::list, LOG_WARNING, and ast_conference::userlist.

Referenced by conf_run().

01442 {
01443    struct ast_conf_user *user;
01444 
01445    AST_LIST_TRAVERSE(&conf->userlist, user, list) {
01446       if (user == sender)
01447          continue;
01448       if (ast_write(user->chan, f) < 0)
01449          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01450    }
01451 }

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

Definition at line 1664 of file app_meetme.c.

References volume::actual, ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, announce_thread(), ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethreadlock, announce_listitem::announcetype, ao2_alloc, ao2_ref, ast_calloc, ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_cond_signal(), ast_config_AST_SPOOL_DIR, AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, ast_devstate_changed(), AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_silence(), ast_exists_extension(), ast_filedelete(), AST_FORMAT_SLINEAR, ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_free, ast_frfree, AST_FRIENDLY_OFFSET, ast_goto_if_exists(), ast_hangup(), ast_indicate(), AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LAST, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), ast_moh_start(), ast_moh_stop(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_read(), ast_read_noaudio(), ast_realtime_require_field(), ast_record_review(), ast_request(), ast_safe_sleep(), ast_samp2tv(), ast_say_digits(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_translate(), ast_translator_build_path(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_update_realtime(), ast_verb, ast_waitfor_nandfds(), ast_waitstream(), ast_write(), ast_channel::audiohooks, buf, can_write(), careful_write(), ast_conference::chan, ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, conf_flush(), CONF_HASJOIN, CONF_HASLEFT, conf_play(), conf_queue_dtmf(), CONF_SIZE, conf_start_moh(), announce_listitem::confchan, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_DURATION_LIMIT, CONFFLAG_DURATION_STOP, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_KEYEXIT, CONFFLAG_KICK_CONTINUE, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_SLA_STATION, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, announce_listitem::confusers, ast_channel::context, ast_conf_user::dahdichannel, ast_conference::dahdiconf, ast_frame::data, ast_frame::datalen, volume::desired, dtmfstr, ast_conf_user::end_sound, ast_conference::endalert, ast_conference::endtime, ENTER, errno, EVENT_FLAG_CALL, exitcontext, f, ast_channel::fds, ast_frame::frametype, ast_conf_user::jointime, ast_conf_user::kicktime, announce_listitem::language, ast_conference::lchan, LEAVE, ast_conf_user::listen, ast_conference::listenlock, ast_conference::locked, LOG_WARNING, ast_channel::macrocontext, manager_event, ast_conference::markedusers, ast_conference::maxusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, ast_channel::monitor, announce_listitem::namerecloc, ast_conf_user::namerecloc, ast_frame::offset, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_EXITKEYS, OPT_ARG_MOH_CLASS, OPT_ARG_WAITMARKED, ast_conference::origframe, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_conf_user::play_warning, ast_conference::playlock, ast_frame::ptr, ast_channel::rawwriteformat, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, reset_volumes(), RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, S_OR, ast_frame::samples, sec, set_talk_volume(), set_user_talking(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_conf_user::start_time, strsep(), ast_frame::subclass, ast_conf_user::talk, ast_conf_user::talking, ast_channel::tech, THRESHOLD_SILENCE, ast_conf_user::timelimit, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_conference::uniqueid, ast_conf_user::user_no, ast_conf_user::userflags, ast_conference::userlist, ast_conference::users, var, VOL_DOWN, VOL_UP, ast_conf_user::warning_freq, and ast_conf_user::warning_sound.

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

01665 {
01666    struct ast_conf_user *user = NULL;
01667    struct ast_conf_user *usr = NULL;
01668    int fd;
01669    struct dahdi_confinfo dahdic, dahdic_empty;
01670    struct ast_frame *f;
01671    struct ast_channel *c;
01672    struct ast_frame fr;
01673    int outfd;
01674    int ms;
01675    int nfds;
01676    int res;
01677    int retrydahdi;
01678    int origfd;
01679    int musiconhold = 0, mohtempstopped = 0;
01680    int firstpass = 0;
01681    int lastmarked = 0;
01682    int currentmarked = 0;
01683    int ret = -1;
01684    int x;
01685    int menu_active = 0;
01686    int talkreq_manager = 0;
01687    int using_pseudo = 0;
01688    int duration = 20;
01689    int hr, min, sec;
01690    int sent_event = 0;
01691    int checked = 0;
01692    int announcement_played = 0;
01693    struct timeval now;
01694    struct ast_dsp *dsp = NULL;
01695    struct ast_app *agi_app;
01696    char *agifile;
01697    const char *agifiledefault = "conf-background.agi", *tmpvar;
01698    char meetmesecs[30] = "";
01699    char exitcontext[AST_MAX_CONTEXT] = "";
01700    char recordingtmp[AST_MAX_EXTENSION] = "";
01701    char members[10] = "";
01702    int dtmf, opt_waitmarked_timeout = 0;
01703    time_t timeout = 0;
01704    struct dahdi_bufferinfo bi;
01705    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
01706    char *buf = __buf + AST_FRIENDLY_OFFSET;
01707    char *exitkeys = NULL;
01708    unsigned int calldurationlimit = 0;
01709    long timelimit = 0;
01710    long play_warning = 0;
01711    long warning_freq = 0;
01712    const char *warning_sound = NULL;
01713    const char *end_sound = NULL;
01714    char *parse;   
01715    long time_left_ms = 0;
01716    struct timeval nexteventts = { 0, };
01717    int to;
01718    int setusercount = 0;
01719    int confsilence = 0, totalsilence = 0;
01720 
01721    if (!(user = ast_calloc(1, sizeof(*user))))
01722       return ret;
01723 
01724    /* Possible timeout waiting for marked user */
01725    if ((confflags & CONFFLAG_WAITMARKED) &&
01726       !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
01727       (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
01728       (opt_waitmarked_timeout > 0)) {
01729       timeout = time(NULL) + opt_waitmarked_timeout;
01730    }
01731       
01732    if ((confflags & CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
01733       calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
01734       ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
01735    }
01736    
01737    if ((confflags & CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
01738       char *limit_str, *warning_str, *warnfreq_str;
01739       const char *var;
01740  
01741       parse = optargs[OPT_ARG_DURATION_LIMIT];
01742       limit_str = strsep(&parse, ":");
01743       warning_str = strsep(&parse, ":");
01744       warnfreq_str = parse;
01745  
01746       timelimit = atol(limit_str);
01747       if (warning_str)
01748          play_warning = atol(warning_str);
01749       if (warnfreq_str)
01750          warning_freq = atol(warnfreq_str);
01751  
01752       if (!timelimit) {
01753          timelimit = play_warning = warning_freq = 0;
01754          warning_sound = NULL;
01755       } else if (play_warning > timelimit) {       
01756          if (!warning_freq) {
01757             play_warning = 0;
01758          } else {
01759             while (play_warning > timelimit)
01760                play_warning -= warning_freq;
01761             if (play_warning < 1)
01762                play_warning = warning_freq = 0;
01763          }
01764       }
01765       
01766       ast_channel_lock(chan);
01767       if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
01768          var = ast_strdupa(var);
01769       }
01770       ast_channel_unlock(chan);
01771 
01772       warning_sound = var ? var : "timeleft";
01773       
01774       ast_channel_lock(chan);
01775       if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
01776          var = ast_strdupa(var);
01777       }
01778       ast_channel_unlock(chan);
01779       
01780       end_sound = var ? var : NULL;
01781          
01782       /* undo effect of S(x) in case they are both used */
01783       calldurationlimit = 0;
01784       /* more efficient do it like S(x) does since no advanced opts */
01785       if (!play_warning && !end_sound && timelimit) { 
01786          calldurationlimit = timelimit / 1000;
01787          timelimit = play_warning = warning_freq = 0;
01788       } else {
01789          ast_debug(2, "Limit Data for this call:\n");
01790          ast_debug(2, "- timelimit     = %ld\n", timelimit);
01791          ast_debug(2, "- play_warning  = %ld\n", play_warning);
01792          ast_debug(2, "- warning_freq  = %ld\n", warning_freq);
01793          ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
01794          ast_debug(2, "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
01795       }
01796    }
01797 
01798    /* Get exit keys */
01799    if ((confflags & CONFFLAG_KEYEXIT)) {
01800       if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
01801          exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
01802       else
01803          exitkeys = ast_strdupa("#"); /* Default */
01804    }
01805    
01806    if (confflags & CONFFLAG_RECORDCONF) {
01807       if (!conf->recordingfilename) {
01808          const char *var;
01809          ast_channel_lock(chan);
01810          if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
01811             conf->recordingfilename = ast_strdup(var);
01812          }
01813          if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
01814             conf->recordingformat = ast_strdup(var);
01815          }
01816          ast_channel_unlock(chan);
01817          if (!conf->recordingfilename) {
01818             snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
01819             conf->recordingfilename = ast_strdup(recordingtmp);
01820          }
01821          if (!conf->recordingformat) {
01822             conf->recordingformat = ast_strdup("wav");
01823          }
01824          ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
01825                 conf->confno, conf->recordingfilename, conf->recordingformat);
01826       }
01827    }
01828 
01829    ast_mutex_lock(&conf->recordthreadlock);
01830    if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
01831       ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
01832       ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
01833       dahdic.chan = 0;
01834       dahdic.confno = conf->dahdiconf;
01835       dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01836       if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
01837          ast_log(LOG_WARNING, "Error starting listen channel\n");
01838          ast_hangup(conf->lchan);
01839          conf->lchan = NULL;
01840       } else {
01841          ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
01842       }
01843    }
01844    ast_mutex_unlock(&conf->recordthreadlock);
01845 
01846    ast_mutex_lock(&conf->announcethreadlock);
01847    if ((conf->announcethread == AST_PTHREADT_NULL) && !(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
01848       ast_mutex_init(&conf->announcelistlock);
01849       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01850       ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
01851    }
01852    ast_mutex_unlock(&conf->announcethreadlock);
01853 
01854    time(&user->jointime);
01855    
01856    user->timelimit = timelimit;
01857    user->play_warning = play_warning;
01858    user->warning_freq = warning_freq;
01859    user->warning_sound = warning_sound;
01860    user->end_sound = end_sound;  
01861    
01862    if (calldurationlimit > 0) {
01863       time(&user->kicktime);
01864       user->kicktime = user->kicktime + calldurationlimit;
01865    }
01866    
01867    if (ast_tvzero(user->start_time))
01868       user->start_time = ast_tvnow();
01869    time_left_ms = user->timelimit;
01870    
01871    if (user->timelimit) {
01872       nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
01873       nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
01874    }
01875 
01876    if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
01877       /* Sorry, but this conference is locked! */  
01878       if (!ast_streamfile(chan, "conf-locked", chan->language))
01879          ast_waitstream(chan, "");
01880       goto outrun;
01881    }
01882 
01883       ast_mutex_lock(&conf->playlock);
01884 
01885    if (AST_LIST_EMPTY(&conf->userlist))
01886       user->user_no = 1;
01887    else
01888       user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
01889 
01890    if (rt_schedule && conf->maxusers)
01891       if (conf->users >= conf->maxusers) {
01892          /* Sorry, but this confernce has reached the participant limit! */   
01893          if (!ast_streamfile(chan, "conf-full", chan->language))
01894             ast_waitstream(chan, "");
01895          ast_mutex_unlock(&conf->playlock);
01896          user->user_no = 0;
01897          goto outrun;
01898       }
01899 
01900    AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
01901 
01902    user->chan = chan;
01903    user->userflags = confflags;
01904    user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
01905    user->talking = -1;
01906 
01907    ast_mutex_unlock(&conf->playlock);
01908 
01909    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
01910       char destdir[PATH_MAX];
01911 
01912       snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
01913 
01914       if (ast_mkdir(destdir, 0777) != 0) {
01915          ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
01916          goto outrun;
01917       }
01918 
01919       snprintf(user->namerecloc, sizeof(user->namerecloc),
01920           "%s/meetme-username-%s-%d", destdir,
01921           conf->confno, user->user_no);
01922       if (confflags & CONFFLAG_INTROUSERNOREVIEW)
01923          res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
01924       else
01925          res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
01926       if (res == -1)
01927          goto outrun;
01928    }
01929 
01930    ast_mutex_lock(&conf->playlock);
01931 
01932    if (confflags & CONFFLAG_MARKEDUSER)
01933       conf->markedusers++;
01934    conf->users++;
01935    if (rt_log_members) {
01936       /* Update table */
01937       snprintf(members, sizeof(members), "%d", conf->users);
01938       ast_realtime_require_field("meetme",
01939          "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
01940          "members", RQ_UINTEGER1, strlen(members),
01941          NULL);
01942       ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
01943    }
01944    setusercount = 1;
01945 
01946    /* This device changed state now - if this is the first user */
01947    if (conf->users == 1)
01948       ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
01949 
01950    ast_mutex_unlock(&conf->playlock);
01951 
01952    /* return the unique ID of the conference */
01953    pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
01954 
01955    if (confflags & CONFFLAG_EXIT_CONTEXT) {
01956       ast_channel_lock(chan);
01957       if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
01958          ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
01959       } else if (!ast_strlen_zero(chan->macrocontext)) {
01960          ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
01961       } else {
01962          ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
01963       }
01964       ast_channel_unlock(chan);
01965    }
01966 
01967    if (!(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
01968       if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
01969          if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
01970             ast_waitstream(chan, "");
01971       if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
01972          if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
01973             ast_waitstream(chan, "");
01974    }
01975 
01976    if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
01977       int keepplaying = 1;
01978 
01979       if (conf->users == 2) { 
01980          if (!ast_streamfile(chan, "conf-onlyone", chan->language)) {
01981             res = ast_waitstream(chan, AST_DIGIT_ANY);
01982             ast_stopstream(chan);
01983             if (res > 0)
01984                keepplaying = 0;
01985             else if (res == -1)
01986                goto outrun;
01987          }
01988       } else { 
01989          if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
01990             res = ast_waitstream(chan, AST_DIGIT_ANY);
01991             ast_stopstream(chan);
01992             if (res > 0)
01993                keepplaying = 0;
01994             else if (res == -1)
01995                goto outrun;
01996          }
01997          if (keepplaying) {
01998             res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
01999             if (res > 0)
02000                keepplaying = 0;
02001             else if (res == -1)
02002                goto outrun;
02003          }
02004          if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
02005             res = ast_waitstream(chan, AST_DIGIT_ANY);
02006             ast_stopstream(chan);
02007             if (res > 0)
02008                keepplaying = 0;
02009             else if (res == -1) 
02010                goto outrun;
02011          }
02012       }
02013    }
02014 
02015    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02016       /* We're leaving this alone until the state gets changed to up */
02017       ast_indicate(chan, -1);
02018    }
02019 
02020    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
02021       ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
02022       goto outrun;
02023    }
02024 
02025    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
02026       ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
02027       goto outrun;
02028    }
02029 
02030    retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
02031    user->dahdichannel = !retrydahdi;
02032 
02033  dahdiretry:
02034    origfd = chan->fds[0];
02035    if (retrydahdi) {
02036       /* open pseudo in non-blocking mode */
02037       fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
02038       if (fd < 0) {
02039          ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
02040          goto outrun;
02041       }
02042       using_pseudo = 1;
02043       /* Setup buffering information */
02044       memset(&bi, 0, sizeof(bi));
02045       bi.bufsize = CONF_SIZE / 2;
02046       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
02047       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
02048       bi.numbufs = audio_buffers;
02049       if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
02050          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
02051          close(fd);
02052          goto outrun;
02053       }
02054       x = 1;
02055       if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
02056          ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
02057          close(fd);
02058          goto outrun;
02059       }
02060       nfds = 1;
02061    } else {
02062       /* XXX Make sure we're not running on a pseudo channel XXX */
02063       fd = chan->fds[0];
02064       nfds = 0;
02065    }
02066    memset(&dahdic, 0, sizeof(dahdic));
02067    memset(&dahdic_empty, 0, sizeof(dahdic_empty));
02068    /* Check to see if we're in a conference... */
02069    dahdic.chan = 0;  
02070    if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
02071       ast_log(LOG_WARNING, "Error getting conference\n");
02072       close(fd);
02073       goto outrun;
02074    }
02075    if (dahdic.confmode) {
02076       /* Whoa, already in a conference...  Retry... */
02077       if (!retrydahdi) {
02078          ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
02079          retrydahdi = 1;
02080          goto dahdiretry;
02081       }
02082    }
02083    memset(&dahdic, 0, sizeof(dahdic));
02084    /* Add us to the conference */
02085    dahdic.chan = 0;  
02086    dahdic.confno = conf->dahdiconf;
02087 
02088    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02089       struct announce_listitem *item;
02090       if (!(item = ao2_alloc(sizeof(*item), NULL)))
02091          return -1;
02092       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02093       ast_copy_string(item->language, chan->language, sizeof(item->language));
02094       item->confchan = conf->chan;
02095       item->confusers = conf->users;
02096       item->announcetype = CONF_HASJOIN;
02097       ast_mutex_lock(&conf->announcelistlock);
02098       ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
02099       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02100       ast_cond_signal(&conf->announcelist_addition);
02101       ast_mutex_unlock(&conf->announcelistlock);
02102 
02103       while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
02104          ;
02105       }
02106       ao2_ref(item, -1);
02107    }
02108 
02109    if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers)
02110       dahdic.confmode = DAHDI_CONF_CONF;
02111    else if (confflags & CONFFLAG_MONITOR)
02112       dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02113    else if (confflags & CONFFLAG_TALKER)
02114       dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02115    else 
02116       dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02117 
02118    if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02119       ast_log(LOG_WARNING, "Error setting conference\n");
02120       close(fd);
02121       goto outrun;
02122    }
02123    ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf);
02124 
02125    if (!sent_event) {
02126       manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
02127                  "Channel: %s\r\n"
02128                  "Uniqueid: %s\r\n"
02129             "Meetme: %s\r\n"
02130             "Usernum: %d\r\n"
02131             "CallerIDnum: %s\r\n"
02132                   "CallerIDname: %s\r\n",
02133                   chan->name, chan->uniqueid, conf->confno, 
02134             user->user_no,
02135             S_OR(user->chan->cid.cid_num, "<unknown>"),
02136             S_OR(user->chan->cid.cid_name, "<unknown>")
02137             );
02138       sent_event = 1;
02139    }
02140 
02141    if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
02142       firstpass = 1;
02143       if (!(confflags & CONFFLAG_QUIET))
02144          if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
02145             conf_play(chan, conf, ENTER);
02146    }
02147 
02148    conf_flush(fd, chan);
02149 
02150    if (!(dsp = ast_dsp_new())) {
02151       ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
02152       res = -1;
02153    }
02154 
02155    if (confflags & CONFFLAG_AGI) {
02156       /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
02157          or use default filename of conf-background.agi */
02158 
02159       ast_channel_lock(chan);
02160       if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
02161          agifile = ast_strdupa(tmpvar);
02162       } else {
02163          agifile = ast_strdupa(agifiledefault);
02164       }
02165       ast_channel_unlock(chan);
02166       
02167       if (user->dahdichannel) {
02168          /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
02169          x = 1;
02170          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02171       }
02172       /* Find a pointer to the agi app and execute the script */
02173       agi_app = pbx_findapp("agi");
02174       if (agi_app) {
02175          ret = pbx_exec(chan, agi_app, agifile);
02176       } else {
02177          ast_log(LOG_WARNING, "Could not find application (agi)\n");
02178          ret = -2;
02179       }
02180       if (user->dahdichannel) {
02181          /*  Remove CONFMUTE mode on DAHDI channel */
02182          x = 0;
02183          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02184       }
02185    } else {
02186       if (user->dahdichannel && (confflags & CONFFLAG_STARMENU)) {
02187          /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
02188          x = 1;
02189          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02190       }  
02191       for (;;) {
02192          int menu_was_active = 0;
02193 
02194          outfd = -1;
02195          ms = -1;
02196          now = ast_tvnow();
02197 
02198          if (rt_schedule) {
02199             if (now.tv_sec % 60 == 0) {
02200                if (!checked) {
02201                   if (now.tv_sec >= conf->endtime) {
02202                      goto outrun;
02203                   }
02204 
02205                   if (!announcement_played && conf->endalert) {
02206                      if (now.tv_sec + conf->endalert >= conf->endtime) {
02207                         if (!ast_streamfile(chan, "conf-will-end-in", chan->language))
02208                            ast_waitstream(chan, "");
02209                         ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language);
02210                         if (!ast_streamfile(chan, "minutes", chan->language))
02211                            ast_waitstream(chan, "");
02212                         announcement_played = 1;
02213                      }
02214                   }
02215                   checked = 1;
02216                   
02217                }
02218             } else {
02219                checked = 0;
02220             }
02221          }
02222 
02223          if (user->kicktime && (user->kicktime <= now.tv_sec)) 
02224             break;
02225   
02226          to = -1;
02227          if (user->timelimit) {
02228             int minutes = 0, seconds = 0, remain = 0;
02229  
02230             to = ast_tvdiff_ms(nexteventts, now);
02231             if (to < 0)
02232                to = 0;
02233             time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
02234             if (time_left_ms < to)
02235                to = time_left_ms;
02236    
02237             if (time_left_ms <= 0) {
02238                if (user->end_sound) {                 
02239                   res = ast_streamfile(chan, user->end_sound, chan->language);
02240                   res = ast_waitstream(chan, "");
02241                }
02242                break;
02243             }
02244             
02245             if (!to) {
02246                if (time_left_ms >= 5000) {                  
02247                   
02248                   remain = (time_left_ms + 500) / 1000;
02249                   if (remain / 60 >= 1) {
02250                      minutes = remain / 60;
02251                      seconds = remain % 60;
02252                   } else {
02253                      seconds = remain;
02254                   }
02255                   
02256                   /* force the time left to round up if appropriate */
02257                   if (user->warning_sound && user->play_warning) {
02258                      if (!strcmp(user->warning_sound, "timeleft")) {
02259                         
02260                         res = ast_streamfile(chan, "vm-youhave", chan->language);
02261                         res = ast_waitstream(chan, "");
02262                         if (minutes) {
02263                            res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL);
02264                            res = ast_streamfile(chan, "queue-minutes", chan->language);
02265                            res = ast_waitstream(chan, "");
02266                         }
02267                         if (seconds) {
02268                            res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL);
02269                            res = ast_streamfile(chan, "queue-seconds", chan->language);
02270                            res = ast_waitstream(chan, "");
02271                         }
02272                      } else {
02273                         res = ast_streamfile(chan, user->warning_sound, chan->language);
02274                         res = ast_waitstream(chan, "");
02275                      }
02276                   }
02277                }
02278                if (user->warning_freq)
02279                   nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
02280                else
02281                   nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
02282             }
02283          }
02284 
02285          now = ast_tvnow();
02286          if (timeout && now.tv_sec >= timeout)
02287             break;
02288 
02289          /* if we have just exited from the menu, and the user had a channel-driver
02290             volume adjustment, restore it
02291          */
02292          if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
02293             set_talk_volume(user, user->listen.desired);
02294 
02295          menu_was_active = menu_active;
02296 
02297          currentmarked = conf->markedusers;
02298          if (!(confflags & CONFFLAG_QUIET) &&
02299              (confflags & CONFFLAG_MARKEDUSER) &&
02300              (confflags & CONFFLAG_WAITMARKED) &&
02301              lastmarked == 0) {
02302             if (currentmarked == 1 && conf->users > 1) {
02303                ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
02304                if (conf->users - 1 == 1) {
02305                   if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
02306                      ast_waitstream(chan, "");
02307                } else {
02308                   if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
02309                      ast_waitstream(chan, "");
02310                }
02311             }
02312             if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
02313                if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
02314                   ast_waitstream(chan, "");
02315          }
02316 
02317          /* Update the struct with the actual confflags */
02318          user->userflags = confflags;
02319 
02320          if (confflags & CONFFLAG_WAITMARKED) {
02321             if (currentmarked == 0) {
02322                if (lastmarked != 0) {
02323                   if (!(confflags & CONFFLAG_QUIET))
02324                      if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
02325                         ast_waitstream(chan, "");
02326                   if (confflags & CONFFLAG_MARKEDEXIT) {
02327                      if (confflags & CONFFLAG_KICK_CONTINUE)
02328                         ret = 0;
02329                      break;
02330                   } else {
02331                      dahdic.confmode = DAHDI_CONF_CONF;
02332                      if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02333                         ast_log(LOG_WARNING, "Error setting conference\n");
02334                         close(fd);
02335                         goto outrun;
02336                      }
02337                   }
02338                }
02339                if (!musiconhold && (confflags & CONFFLAG_MOH)) {
02340                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02341                   musiconhold = 1;
02342                }
02343             } else if (currentmarked >= 1 && lastmarked == 0) {
02344                /* Marked user entered, so cancel timeout */
02345                timeout = 0;
02346                if (confflags & CONFFLAG_MONITOR)
02347                   dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02348                else if (confflags & CONFFLAG_TALKER)
02349                   dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02350                else
02351                   dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02352                if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02353                   ast_log(LOG_WARNING, "Error setting conference\n");
02354                   close(fd);
02355                   goto outrun;
02356                }
02357                if (musiconhold && (confflags & CONFFLAG_MOH)) {
02358                   ast_moh_stop(chan);
02359                   musiconhold = 0;
02360                }
02361                if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
02362                   if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
02363                      ast_waitstream(chan, "");
02364                   conf_play(chan, conf, ENTER);
02365                }
02366             }
02367          }
02368 
02369          /* trying to add moh for single person conf */
02370          if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
02371             if (conf->users == 1) {
02372                if (!musiconhold) {
02373                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02374                   musiconhold = 1;
02375                } 
02376             } else {
02377                if (musiconhold) {
02378                   ast_moh_stop(chan);
02379                   musiconhold = 0;
02380                }
02381             }
02382          }
02383          
02384          /* Leave if the last marked user left */
02385          if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
02386             if (confflags & CONFFLAG_KICK_CONTINUE)
02387                ret = 0;
02388             else
02389                ret = -1;
02390             break;
02391          }
02392    
02393          /* Check if my modes have changed */
02394 
02395          /* If I should be muted but am still talker, mute me */
02396          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
02397             dahdic.confmode ^= DAHDI_CONF_TALKER;
02398             if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02399                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02400                ret = -1;
02401                break;
02402             }
02403 
02404             /* Indicate user is not talking anymore - change him to unmonitored state */
02405             if ((confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) {
02406                set_user_talking(chan, conf, user, -1, confflags & CONFFLAG_MONITORTALKER);
02407             }
02408 
02409             manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
02410                   "Channel: %s\r\n"
02411                   "Uniqueid: %s\r\n"
02412                   "Meetme: %s\r\n"
02413                   "Usernum: %i\r\n"
02414                   "Status: on\r\n",
02415                   chan->name, chan->uniqueid, conf->confno, user->user_no);
02416          }
02417 
02418          /* If I should be un-muted but am not talker, un-mute me */
02419          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
02420             dahdic.confmode |= DAHDI_CONF_TALKER;
02421             if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02422                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02423                ret = -1;
02424                break;
02425             }
02426 
02427             manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
02428                   "Channel: %s\r\n"
02429                   "Uniqueid: %s\r\n"
02430                   "Meetme: %s\r\n"
02431                   "Usernum: %i\r\n"
02432                   "Status: off\r\n",
02433                   chan->name, chan->uniqueid, conf->confno, user->user_no);
02434          }
02435          
02436          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
02437             (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
02438             talkreq_manager = 1;
02439 
02440             manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 
02441                      "Channel: %s\r\n"
02442                            "Uniqueid: %s\r\n"
02443                            "Meetme: %s\r\n"
02444                            "Usernum: %i\r\n"
02445                            "Status: on\r\n",
02446                            chan->name, chan->uniqueid, conf->confno, user->user_no);
02447          }
02448 
02449          
02450          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
02451             !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
02452             talkreq_manager = 0;
02453             manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 
02454                      "Channel: %s\r\n"
02455                            "Uniqueid: %s\r\n"
02456                            "Meetme: %s\r\n"
02457                            "Usernum: %i\r\n"
02458                            "Status: off\r\n",
02459                           chan->name, chan->uniqueid, conf->confno, user->user_no);
02460          }
02461          
02462          /* If I have been kicked, exit the conference */
02463          if (user->adminflags & ADMINFLAG_KICKME) {
02464             /* You have been kicked. */
02465             if (!(confflags & CONFFLAG_QUIET) && 
02466                !ast_streamfile(chan, "conf-kicked", chan->language)) {
02467                ast_waitstream(chan, "");
02468             }
02469             ret = 0;
02470             break;
02471          }
02472 
02473          /* Perform an extra hangup check just in case */
02474          if (ast_check_hangup(chan))
02475             break;
02476 
02477          c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
02478 
02479          if (c) {
02480             char dtmfstr[2] = "";
02481 
02482             if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) {
02483                if (using_pseudo) {
02484                   /* Kill old pseudo */
02485                   close(fd);
02486                   using_pseudo = 0;
02487                }
02488                ast_debug(1, "Ooh, something swapped out under us, starting over\n");
02489                retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0);
02490                user->dahdichannel = !retrydahdi;
02491                goto dahdiretry;
02492             }
02493             if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
02494                f = ast_read_noaudio(c);
02495             else
02496                f = ast_read(c);
02497             if (!f)
02498                break;
02499             if (f->frametype == AST_FRAME_DTMF) {
02500                dtmfstr[0] = f->subclass;
02501                dtmfstr[1] = '\0';
02502             }
02503 
02504             if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
02505                if (user->talk.actual)
02506                   ast_frame_adjust_volume(f, user->talk.actual);
02507 
02508                if (confflags & (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER)) {
02509                   if (user->talking == -1)
02510                      user->talking = 0;
02511 
02512                   res = ast_dsp_silence(dsp, f, &totalsilence);
02513                   if (totalsilence < MEETME_DELAYDETECTTALK) {
02514                      set_user_talking(chan, conf, user, 1, confflags & CONFFLAG_MONITORTALKER);
02515                   }
02516                   if (totalsilence > MEETME_DELAYDETECTENDTALK) {
02517                      set_user_talking(chan, conf, user, 0, confflags & CONFFLAG_MONITORTALKER);
02518                   }
02519                }
02520                if (using_pseudo) {
02521                   /* Absolutely do _not_ use careful_write here...
02522                      it is important that we read data from the channel
02523                      as fast as it arrives, and feed it into the conference.
02524                      The buffering in the pseudo channel will take care of any
02525                      timing differences, unless they are so drastic as to lose
02526                      audio frames (in which case carefully writing would only
02527                      have delayed the audio even further).
02528                   */
02529                   /* As it turns out, we do want to use careful write.  We just
02530                      don't want to block, but we do want to at least *try*
02531                      to write out all the samples.
02532                    */
02533                   if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER)) {
02534                      careful_write(fd, f->data.ptr, f->datalen, 0);
02535                   }
02536                }
02537             } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
02538                if (confflags & CONFFLAG_PASS_DTMF)
02539                   conf_queue_dtmf(conf, user, f);
02540                if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
02541                   ast_log(LOG_WARNING, "Error setting conference\n");
02542                   close(fd);
02543                   ast_frfree(f);
02544                   goto outrun;
02545                }
02546 
02547                /* if we are entering the menu, and the user has a channel-driver
02548                   volume adjustment, clear it
02549                */
02550                if (!menu_active && user->talk.desired && !user->talk.actual)
02551                   set_talk_volume(user, 0);
02552 
02553                if (musiconhold) {
02554                      ast_moh_stop(chan);
02555                }
02556                if ((confflags & CONFFLAG_ADMIN)) {
02557                   /* Admin menu */
02558                   if (!menu_active) {
02559                      menu_active = 1;
02560                      /* Record this sound! */
02561                      if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
02562                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02563                         ast_stopstream(chan);
02564                      } else 
02565                         dtmf = 0;
02566                   } else 
02567                      dtmf = f->subclass;
02568                   if (dtmf) {
02569                      switch(dtmf) {
02570                      case '1': /* Un/Mute */
02571                         menu_active = 0;
02572 
02573                         /* for admin, change both admin and use flags */
02574                         if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
02575                            user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02576                         else
02577                            user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02578 
02579                         if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02580                            if (!ast_streamfile(chan, "conf-muted", chan->language))
02581                               ast_waitstream(chan, "");
02582                         } else {
02583                            if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02584                               ast_waitstream(chan, "");
02585                         }
02586                         break;
02587                      case '2': /* Un/Lock the Conference */
02588                         menu_active = 0;
02589                         if (conf->locked) {
02590                            conf->locked = 0;
02591                            if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
02592                               ast_waitstream(chan, "");
02593                         } else {
02594                            conf->locked = 1;
02595                            if (!ast_streamfile(chan, "conf-lockednow", chan->language))
02596                               ast_waitstream(chan, "");
02597                         }
02598                         break;
02599                      case '3': /* Eject last user */
02600                         menu_active = 0;
02601                         usr = AST_LIST_LAST(&conf->userlist);
02602                         if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
02603                            if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02604                               ast_waitstream(chan, "");
02605                         } else 
02606                            usr->adminflags |= ADMINFLAG_KICKME;
02607                         ast_stopstream(chan);
02608                         break;   
02609                      case '4':
02610                         tweak_listen_volume(user, VOL_DOWN);
02611                         break;
02612                      case '6':
02613                         tweak_listen_volume(user, VOL_UP);
02614                         break;
02615                      case '7':
02616                         tweak_talk_volume(user, VOL_DOWN);
02617                         break;
02618                      case '8':
02619                         menu_active = 0;
02620                         break;
02621                      case '9':
02622                         tweak_talk_volume(user, VOL_UP);
02623                         break;
02624                      default:
02625                         menu_active = 0;
02626                         /* Play an error message! */
02627                         if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02628                            ast_waitstream(chan, "");
02629                         break;
02630                      }
02631                   }
02632                } else {
02633                   /* User menu */
02634                   if (!menu_active) {
02635                      menu_active = 1;
02636                      if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
02637                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02638                         ast_stopstream(chan);
02639                      } else
02640                         dtmf = 0;
02641                   } else 
02642                      dtmf = f->subclass;
02643                   if (dtmf) {
02644                      switch(dtmf) {
02645                      case '1': /* Un/Mute */
02646                         menu_active = 0;
02647 
02648                         /* user can only toggle the self-muted state */
02649                         user->adminflags ^= ADMINFLAG_SELFMUTED;
02650 
02651                         /* they can't override the admin mute state */
02652                         if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02653                            if (!ast_streamfile(chan, "conf-muted", chan->language))
02654                               ast_waitstream(chan, "");
02655                         } else {
02656                            if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02657                               ast_waitstream(chan, "");
02658                         }
02659                         break;
02660                      case '2':
02661                         menu_active = 0;
02662                         if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
02663                            user->adminflags |= ADMINFLAG_T_REQUEST;
02664                            
02665                         if (user->adminflags & ADMINFLAG_T_REQUEST)
02666                            if (!ast_streamfile(chan, "beep", chan->language))
02667                               ast_waitstream(chan, "");
02668                         break;
02669                      case '4':
02670                         tweak_listen_volume(user, VOL_DOWN);
02671                         break;
02672                      case '6':
02673                         tweak_listen_volume(user, VOL_UP);
02674                         break;
02675                      case '7':
02676                         tweak_talk_volume(user, VOL_DOWN);
02677                         break;
02678                      case '8':
02679                         menu_active = 0;
02680                         break;
02681                      case '9':
02682                         tweak_talk_volume(user, VOL_UP);
02683                         break;
02684                      default:
02685                         menu_active = 0;
02686                         if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02687                            ast_waitstream(chan, "");
02688                         break;
02689                      }
02690                   }
02691                }
02692                if (musiconhold)
02693                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02694 
02695                if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02696                   ast_log(LOG_WARNING, "Error setting conference\n");
02697                   close(fd);
02698                   ast_frfree(f);
02699                   goto outrun;
02700                }
02701 
02702                conf_flush(fd, chan);
02703             /* Since this option could absorb dtmf meant for the previous (menu), we have to check this one last */
02704             } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
02705                if (confflags & CONFFLAG_PASS_DTMF)
02706                   conf_queue_dtmf(conf, user, f);
02707 
02708                if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
02709                   ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
02710                   ret = 0;
02711                   ast_frfree(f);
02712                   break;
02713                } else {
02714                   ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
02715                }
02716             } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) {
02717                pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
02718                   
02719                if (confflags & CONFFLAG_PASS_DTMF)
02720                   conf_queue_dtmf(conf, user, f);
02721                ret = 0;
02722                ast_frfree(f);
02723                break;
02724             } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
02725                && confflags & CONFFLAG_PASS_DTMF) {
02726                conf_queue_dtmf(conf, user, f);
02727             } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
02728                switch (f->subclass) {
02729                case AST_CONTROL_HOLD:
02730                   sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
02731                   break;
02732                default:
02733                   break;
02734                }
02735             } else if (f->frametype == AST_FRAME_NULL) {
02736                /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
02737             } else {
02738                ast_debug(1, 
02739                   "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
02740                   chan->name, f->frametype, f->subclass);
02741             }
02742             ast_frfree(f);
02743          } else if (outfd > -1) {
02744             res = read(outfd, buf, CONF_SIZE);
02745             if (res > 0) {
02746                memset(&fr, 0, sizeof(fr));
02747                fr.frametype = AST_FRAME_VOICE;
02748                fr.subclass = AST_FORMAT_SLINEAR;
02749                fr.datalen = res;
02750                fr.samples = res / 2;
02751                fr.data.ptr = buf;
02752                fr.offset = AST_FRIENDLY_OFFSET;
02753                if (!user->listen.actual &&
02754                   ((confflags & CONFFLAG_MONITOR) ||
02755                    (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
02756                    (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
02757                    )) {
02758                   int idx;
02759                   for (idx = 0; idx < AST_FRAME_BITS; idx++)
02760                      if (chan->rawwriteformat & (1 << idx))
02761                         break;
02762                   if (idx >= AST_FRAME_BITS)
02763                      goto bailoutandtrynormal;
02764                   ast_mutex_lock(&conf->listenlock);
02765                   if (!conf->transframe[idx]) {
02766                      if (conf->origframe) {
02767                         if (!conf->transpath[idx])
02768                            conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR);
02769                         if (conf->transpath[idx]) {
02770                            conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
02771                            if (!conf->transframe[idx])
02772                               conf->transframe[idx] = &ast_null_frame;
02773                         }
02774                      }
02775                   }
02776                   if (conf->transframe[idx]) {
02777                      if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
02778                          can_write(chan, confflags)) {
02779                         struct ast_frame *cur;
02780                         if (musiconhold && !ast_dsp_silence(dsp, conf->transframe[idx], &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
02781                            ast_moh_stop(chan);
02782                            mohtempstopped = 1;
02783                         }
02784 
02785                         /* the translator may have returned a list of frames, so
02786                            write each one onto the channel
02787                         */
02788                         for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
02789                            if (ast_write(chan, cur)) {
02790                               ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02791                               break;
02792                            }
02793                         }
02794                         if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
02795                            mohtempstopped = 0;
02796                            ast_moh_start(chan, NULL, NULL);
02797                         }
02798                      }
02799                   } else {
02800                      ast_mutex_unlock(&conf->listenlock);
02801                      goto bailoutandtrynormal;
02802                   }
02803                   ast_mutex_unlock(&conf->listenlock);
02804                } else {
02805 bailoutandtrynormal:
02806                   if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
02807                      ast_moh_stop(chan);
02808                      mohtempstopped = 1;
02809                   }
02810                   if (user->listen.actual)
02811                      ast_frame_adjust_volume(&fr, user->listen.actual);
02812                   if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
02813                      ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02814                   }
02815                   if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
02816                      mohtempstopped = 0;
02817                      ast_moh_start(chan, NULL, NULL);
02818                   }
02819                }
02820             } else 
02821                ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
02822          }
02823          lastmarked = currentmarked;
02824       }
02825    }
02826 
02827    if (musiconhold)
02828       ast_moh_stop(chan);
02829    
02830    if (using_pseudo)
02831       close(fd);
02832    else {
02833       /* Take out of conference */
02834       dahdic.chan = 0;  
02835       dahdic.confno = 0;
02836       dahdic.confmode = 0;
02837       if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02838          ast_log(LOG_WARNING, "Error setting conference\n");
02839       }
02840    }
02841 
02842    reset_volumes(user);
02843 
02844    if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
02845       conf_play(chan, conf, LEAVE);
02846 
02847    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02848       struct announce_listitem *item;
02849       if (!(item = ao2_alloc(sizeof(*item), NULL)))
02850          return -1;
02851       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02852       ast_copy_string(item->language, chan->language, sizeof(item->language));
02853       item->confchan = conf->chan;
02854       item->confusers = conf->users;
02855       item->announcetype = CONF_HASLEFT;
02856       ast_mutex_lock(&conf->announcelistlock);
02857       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02858       ast_cond_signal(&conf->announcelist_addition);
02859       ast_mutex_unlock(&conf->announcelistlock);
02860    } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) {
02861       /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
02862       ast_filedelete(user->namerecloc, NULL);
02863    }
02864 
02865  outrun:
02866    AST_LIST_LOCK(&confs);
02867 
02868    if (dsp)
02869       ast_dsp_free(dsp);
02870    
02871    if (user->user_no) { /* Only cleanup users who really joined! */
02872       now = ast_tvnow();
02873       hr = (now.tv_sec - user->jointime) / 3600;
02874       min = ((now.tv_sec - user->jointime) % 3600) / 60;
02875       sec = (now.tv_sec - user->jointime) % 60;
02876 
02877       if (sent_event) {
02878          manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
02879                   "Channel: %s\r\n"
02880                   "Uniqueid: %s\r\n"
02881                   "Meetme: %s\r\n"
02882                   "Usernum: %d\r\n"
02883                   "CallerIDNum: %s\r\n"
02884                   "CallerIDName: %s\r\n"
02885                   "Duration: %ld\r\n",
02886                   chan->name, chan->uniqueid, conf->confno, 
02887                   user->user_no,
02888                   S_OR(user->chan->cid.cid_num, "<unknown>"),
02889                   S_OR(user->chan->cid.cid_name, "<unknown>"),
02890                   (long)(now.tv_sec - user->jointime));
02891       }
02892 
02893       if (setusercount) {
02894          conf->users--;
02895          if (rt_log_members) {
02896             /* Update table */
02897             snprintf(members, sizeof(members), "%d", conf->users);
02898             ast_realtime_require_field("meetme",
02899                "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
02900                "members", RQ_UINTEGER1, strlen(members),
02901                NULL);
02902             ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
02903          }
02904          if (confflags & CONFFLAG_MARKEDUSER) 
02905             conf->markedusers--;
02906       }
02907       /* Remove ourselves from the list */
02908       AST_LIST_REMOVE(&conf->userlist, user, list);
02909 
02910       /* Change any states */
02911       if (!conf->users)
02912          ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
02913       
02914       /* Return the number of seconds the user was in the conf */
02915       snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
02916       pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
02917    }
02918    ast_free(user);
02919    AST_LIST_UNLOCK(&confs);
02920 
02921    return ret;
02922 }

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

Definition at line 1543 of file app_meetme.c.

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

Referenced by conf_run().

01544 {
01545    char *original_moh;
01546 
01547    ast_channel_lock(chan);
01548    original_moh = ast_strdupa(chan->musicclass);
01549    ast_string_field_set(chan, musicclass, musicclass);
01550    ast_channel_unlock(chan);
01551 
01552    ast_moh_start(chan, original_moh, NULL);
01553 
01554    ast_channel_lock(chan);
01555    ast_string_field_set(chan, musicclass, original_moh);
01556    ast_channel_unlock(chan);
01557 }

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

The MeetmeCount application.

Definition at line 3162 of file app_meetme.c.

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

Referenced by load_module().

03163 {
03164    int res = 0;
03165    struct ast_conference *conf;
03166    int count;
03167    char *localdata;
03168    char val[80] = "0"; 
03169    AST_DECLARE_APP_ARGS(args,
03170       AST_APP_ARG(confno);
03171       AST_APP_ARG(varname);
03172    );
03173 
03174    if (ast_strlen_zero(data)) {
03175       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
03176       return -1;
03177    }
03178    
03179    if (!(localdata = ast_strdupa(data)))
03180       return -1;
03181 
03182    AST_STANDARD_APP_ARGS(args, localdata);
03183    
03184    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
03185 
03186    if (conf) {
03187       count = conf->users;
03188       dispose_conf(conf);
03189       conf = NULL;
03190    } else
03191       count = 0;
03192 
03193    if (!ast_strlen_zero(args.varname)) {
03194       /* have var so load it and exit */
03195       snprintf(val, sizeof(val), "%d", count);
03196       pbx_builtin_setvar_helper(chan, args.varname, val);
03197    } else {
03198       if (chan->_state != AST_STATE_UP)
03199          ast_answer(chan);
03200       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
03201    }
03202 
03203    return res;
03204 }

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

Definition at line 5217 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

05218 {
05219    struct sla_trunk_ref *trunk_ref;
05220 
05221    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
05222       return NULL;
05223 
05224    trunk_ref->trunk = trunk;
05225 
05226    return trunk_ref;
05227 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 5428 of file app_meetme.c.

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

Referenced by sla_build_station(), and sla_destroy().

05429 {
05430    struct sla_trunk_ref *trunk_ref;
05431 
05432    if (!ast_strlen_zero(station->autocontext)) {
05433       AST_RWLIST_RDLOCK(&sla_trunks);
05434       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05435          char exten[AST_MAX_EXTENSION];
05436          char hint[AST_MAX_APP];
05437          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05438          snprintf(hint, sizeof(hint), "SLA:%s", exten);
05439          ast_context_remove_extension(station->autocontext, exten, 
05440             1, sla_registrar);
05441          ast_context_remove_extension(station->autocontext, hint, 
05442             PRIORITY_HINT, sla_registrar);
05443       }
05444       AST_RWLIST_UNLOCK(&sla_trunks);
05445    }
05446 
05447    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
05448       ast_free(trunk_ref);
05449 
05450    ast_string_field_free_memory(station);
05451    ast_free(station);
05452 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 5414 of file app_meetme.c.

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

Referenced by sla_build_trunk(), and sla_destroy().

05415 {
05416    struct sla_station_ref *station_ref;
05417 
05418    if (!ast_strlen_zero(trunk->autocontext))
05419       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
05420 
05421    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
05422       ast_free(station_ref);
05423 
05424    ast_string_field_free_memory(trunk);
05425    ast_free(trunk);
05426 }

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

Definition at line 4929 of file app_meetme.c.

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

Referenced by sla_station_exec().

04930 {
04931    struct dial_trunk_args *args = data;
04932    struct ast_dial *dial;
04933    char *tech, *tech_data;
04934    enum ast_dial_result dial_res;
04935    char conf_name[MAX_CONFNUM];
04936    struct ast_conference *conf;
04937    struct ast_flags conf_flags = { 0 };
04938    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
04939    const char *cid_name = NULL, *cid_num = NULL;
04940 
04941    if (!(dial = ast_dial_create())) {
04942       ast_mutex_lock(args->cond_lock);
04943       ast_cond_signal(args->cond);
04944       ast_mutex_unlock(args->cond_lock);
04945       return NULL;
04946    }
04947 
04948    tech_data = ast_strdupa(trunk_ref->trunk->device);
04949    tech = strsep(&tech_data, "/");
04950    if (ast_dial_append(dial, tech, tech_data) == -1) {
04951       ast_mutex_lock(args->cond_lock);
04952       ast_cond_signal(args->cond);
04953       ast_mutex_unlock(args->cond_lock);
04954       ast_dial_destroy(dial);
04955       return NULL;
04956    }
04957 
04958    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
04959       cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
04960       ast_free(trunk_ref->chan->cid.cid_name);
04961       trunk_ref->chan->cid.cid_name = NULL;
04962    }
04963    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
04964       cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
04965       ast_free(trunk_ref->chan->cid.cid_num);
04966       trunk_ref->chan->cid.cid_num = NULL;
04967    }
04968 
04969    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
04970 
04971    if (cid_name)
04972       trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
04973    if (cid_num)
04974       trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
04975 
04976    if (dial_res != AST_DIAL_RESULT_TRYING) {
04977       ast_mutex_lock(args->cond_lock);
04978       ast_cond_signal(args->cond);
04979       ast_mutex_unlock(args->cond_lock);
04980       ast_dial_destroy(dial);
04981       return NULL;
04982    }
04983 
04984    for (;;) {
04985       unsigned int done = 0;
04986       switch ((dial_res = ast_dial_state(dial))) {
04987       case AST_DIAL_RESULT_ANSWERED:
04988          trunk_ref->trunk->chan = ast_dial_answered(dial);
04989       case AST_DIAL_RESULT_HANGUP:
04990       case AST_DIAL_RESULT_INVALID:
04991       case AST_DIAL_RESULT_FAILED:
04992       case AST_DIAL_RESULT_TIMEOUT:
04993       case AST_DIAL_RESULT_UNANSWERED:
04994          done = 1;
04995       case AST_DIAL_RESULT_TRYING:
04996       case AST_DIAL_RESULT_RINGING:
04997       case AST_DIAL_RESULT_PROGRESS:
04998       case AST_DIAL_RESULT_PROCEEDING:
04999          break;
05000       }
05001       if (done)
05002          break;
05003    }
05004 
05005    if (!trunk_ref->trunk->chan) {
05006       ast_mutex_lock(args->cond_lock);
05007       ast_cond_signal(args->cond);
05008       ast_mutex_unlock(args->cond_lock);
05009       ast_dial_join(dial);
05010       ast_dial_destroy(dial);
05011       return NULL;
05012    }
05013 
05014    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05015    ast_set_flag(&conf_flags, 
05016       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
05017       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
05018    conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan);
05019 
05020    ast_mutex_lock(args->cond_lock);
05021    ast_cond_signal(args->cond);
05022    ast_mutex_unlock(args->cond_lock);
05023 
05024    if (conf) {
05025       conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
05026       dispose_conf(conf);
05027       conf = NULL;
05028    }
05029 
05030    /* If the trunk is going away, it is definitely now IDLE. */
05031    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05032 
05033    trunk_ref->trunk->chan = NULL;
05034    trunk_ref->trunk->on_hold = 0;
05035 
05036    ast_dial_join(dial);
05037    ast_dial_destroy(dial);
05038 
05039    return NULL;
05040 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Definition at line 1525 of file app_meetme.c.

References ast_atomic_dec_and_test(), AST_LIST_LOCK, AST_LIST_UNLOCK, conf_free(), conf_map, ast_conference::confno, and ast_conference::refcount.

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

01526 {
01527    int res = 0;
01528    int confno_int = 0;
01529 
01530    AST_LIST_LOCK(&confs);
01531    if (ast_atomic_dec_and_test(&conf->refcount)) {
01532       /* Take the conference room number out of an inuse state */
01533       if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01534          conf_map[confno_int] = 0;
01535       conf_free(conf);
01536       res = 1;
01537    }
01538    AST_LIST_UNLOCK(&confs);
01539 
01540    return res;
01541 }

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

Definition at line 3062 of file app_meetme.c.

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

Referenced by conf_exec(), and count_exec().

03064 {
03065    struct ast_config *cfg;
03066    struct ast_variable *var;
03067    struct ast_flags config_flags = { 0 };
03068    struct ast_conference *cnf;
03069 
03070    AST_DECLARE_APP_ARGS(args,
03071       AST_APP_ARG(confno);
03072       AST_APP_ARG(pin);
03073       AST_APP_ARG(pinadmin);
03074    );
03075 
03076    /* Check first in the conference list */
03077    ast_debug(1, "The requested confno is '%s'?\n", confno);
03078    AST_LIST_LOCK(&confs);
03079    AST_LIST_TRAVERSE(&confs, cnf, list) {
03080       ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
03081       if (!strcmp(confno, cnf->confno)) 
03082          break;
03083    }
03084    if (cnf) {
03085       cnf->refcount += refcount;
03086    }
03087    AST_LIST_UNLOCK(&confs);
03088 
03089    if (!cnf) {
03090       if (dynamic) {
03091          /* No need to parse meetme.conf */
03092          ast_debug(1, "Building dynamic conference '%s'\n", confno);
03093          if (dynamic_pin) {
03094             if (dynamic_pin[0] == 'q') {
03095                /* Query the user to enter a PIN */
03096                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
03097                   return NULL;
03098             }
03099             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
03100          } else {
03101             cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
03102          }
03103       } else {
03104          /* Check the config */
03105          cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03106          if (!cfg) {
03107             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
03108             return NULL;
03109          }
03110 
03111          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
03112             char parse[MAX_SETTINGS];
03113 
03114             if (strcasecmp(var->name, "conf"))
03115                continue;
03116 
03117             ast_copy_string(parse, var->value, sizeof(parse));
03118 
03119             AST_STANDARD_APP_ARGS(args, parse);
03120             ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
03121             if (!strcasecmp(args.confno, confno)) {
03122                /* Bingo it's a valid conference */
03123                cnf = build_conf(args.confno,
03124                      S_OR(args.pin, ""),
03125                      S_OR(args.pinadmin, ""),
03126                      make, dynamic, refcount, chan);
03127                break;
03128             }
03129          }
03130          if (!var) {
03131             ast_debug(1, "%s isn't a valid conference\n", confno);
03132          }
03133          ast_config_destroy(cfg);
03134       }
03135    } else if (dynamic_pin) {
03136       /* Correct for the user selecting 'D' instead of 'd' to have
03137          someone join into a conference that has already been created
03138          with a pin. */
03139       if (dynamic_pin[0] == 'q')
03140          dynamic_pin[0] = '\0';
03141    }
03142 
03143    if (cnf) {
03144       if (confflags && !cnf->chan &&
03145           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03146           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03147          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03148          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03149       }
03150       
03151       if (confflags && !cnf->chan &&
03152           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03153          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03154          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03155       }
03156    }
03157 
03158    return cnf;
03159 }

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

Definition at line 2924 of file app_meetme.c.

References ast_clear_flag, ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), ast_mktime(), ast_strdupa, ast_streamfile(), ast_strftime(), ast_test_flag, ast_tvnow(), ast_variables_destroy(), ast_waitstream(), build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, ast_conference::confno, DATE_FORMAT, ast_conference::endalert, ast_conference::endtime, ast_conference::list, LOG_WARNING, ast_conference::maxusers, ast_variable::name, ast_variable::next, ast_conference::refcount, ast_variable::value, and var.

Referenced by conf_exec().

02927 {
02928    struct ast_variable *var;
02929    struct ast_conference *cnf;
02930 
02931    *too_early = 0;
02932 
02933    /* Check first in the conference list */
02934    AST_LIST_LOCK(&confs);
02935    AST_LIST_TRAVERSE(&confs, cnf, list) {
02936       if (!strcmp(confno, cnf->confno)) 
02937          break;
02938    }
02939    if (cnf) {
02940       cnf->refcount += refcount;
02941    }
02942    AST_LIST_UNLOCK(&confs);
02943 
02944    if (!cnf) {
02945       char *pin = NULL, *pinadmin = NULL; /* For temp use */
02946       int maxusers = 0;
02947       struct timeval now;
02948       char currenttime[19] = "";
02949       char eatime[19] = "";
02950       char useropts[32] = "";
02951       char adminopts[32] = "";
02952       struct ast_tm tm, etm;
02953       struct timeval endtime = { .tv_sec = 0 };
02954 
02955       if (rt_schedule) {
02956          now = ast_tvnow();
02957 
02958          ast_localtime(&now, &tm, NULL);
02959          ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02960 
02961          ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
02962 
02963          var = ast_load_realtime("meetme", "confno",
02964             confno, "starttime <= ", currenttime, "endtime >= ",
02965             currenttime, NULL);
02966 
02967          if (!var && fuzzystart) {
02968             now = ast_tvnow();
02969             now.tv_sec += fuzzystart;
02970 
02971             ast_localtime(&now, &tm, NULL);
02972             ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02973             var = ast_load_realtime("meetme", "confno",
02974                confno, "starttime <= ", currenttime, "endtime >= ",
02975                currenttime, NULL);
02976          }
02977 
02978          if (!var && earlyalert) {
02979             now = ast_tvnow();
02980             now.tv_sec += earlyalert;
02981             ast_localtime(&now, &etm, NULL);
02982             ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
02983             var = ast_load_realtime("meetme", "confno",
02984                confno, "starttime <= ", eatime, "endtime >= ",
02985                currenttime, NULL);
02986             if (var)
02987                *too_early = 1;
02988          }
02989 
02990       } else
02991           var = ast_load_realtime("meetme", "confno", confno, NULL);
02992 
02993       if (!var)
02994          return NULL;
02995 
02996       if (rt_schedule && *too_early) {
02997          /* Announce that the caller is early and exit */
02998          if (!ast_streamfile(chan, "conf-has-not-started", chan->language))
02999             ast_waitstream(chan, "");
03000          ast_variables_destroy(var);
03001          return NULL;
03002       }
03003 
03004       while (var) {
03005          if (!strcasecmp(var->name, "pin")) {
03006             pin = ast_strdupa(var->value);
03007          } else if (!strcasecmp(var->name, "adminpin")) {
03008             pinadmin = ast_strdupa(var->value);
03009          } else if (!strcasecmp(var->name, "opts")) {
03010             ast_copy_string(useropts, var->value, sizeof(useropts));
03011          } else if (!strcasecmp(var->name, "maxusers")) {
03012             maxusers = atoi(var->value);
03013          } else if (!strcasecmp(var->name, "adminopts")) {
03014             ast_copy_string(adminopts, var->value, sizeof(adminopts));
03015          } else if (!strcasecmp(var->name, "endtime")) {
03016             union {
03017                struct ast_tm atm;
03018                struct tm tm;
03019             } t = { { 0, }, };
03020             strptime(var->value, "%Y-%m-%d %H:%M:%S", &t.tm);
03021             /* strptime does not determine if a time is
03022              * in DST or not.  Set tm_isdst to -1 to 
03023              * allow ast_mktime to adjust for DST 
03024              * if needed */
03025             t.tm.tm_isdst = -1; 
03026             endtime = ast_mktime(&t.atm, NULL);
03027          }
03028 
03029          var = var->next;
03030       }
03031 
03032       ast_variables_destroy(var);
03033 
03034       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
03035 
03036       if (cnf) {
03037          cnf->maxusers = maxusers;
03038          cnf->endalert = endalert;
03039          cnf->endtime = endtime.tv_sec;
03040       }
03041    }
03042 
03043    if (cnf) {
03044       if (confflags && !cnf->chan &&
03045           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03046           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03047          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03048          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03049       }
03050       
03051       if (confflags && !cnf->chan &&
03052           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03053          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03054          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03055       }
03056    }
03057 
03058    return cnf;
03059 }

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

Definition at line 3453 of file app_meetme.c.

References AST_LIST_TRAVERSE, ast_conf_user::list, ast_conf_user::user_no, and ast_conference::userlist.

Referenced by admin_exec().

03454 {
03455    struct ast_conf_user *user = NULL;
03456    int cid;
03457    
03458    sscanf(callerident, "%30i", &cid);
03459    if (conf && callerident) {
03460       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03461          if (cid == user->user_no)
03462             return user;
03463       }
03464    }
03465    return NULL;
03466 }

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

Definition at line 1559 of file app_meetme.c.

References CONF_HASJOIN, and CONF_HASLEFT.

Referenced by announce_thread().

01560 {
01561    switch (type) {
01562    case CONF_HASLEFT:
01563       return "conf-hasleft";
01564       break;
01565    case CONF_HASJOIN:
01566       return "conf-hasjoin";
01567       break;
01568    default:
01569       return "";
01570    }
01571 }

static char* istalking ( int  x  )  [static]

Definition at line 655 of file app_meetme.c.

Referenced by meetme_cmd().

00656 {
00657    if (x > 0)
00658       return "(talking)";
00659    else if (x < 0)
00660       return "(unmonitored)";
00661    else 
00662       return "(not talking)";
00663 }

static int load_config ( int  reload  )  [static]

Definition at line 5872 of file app_meetme.c.

References ast_log(), load_config_meetme(), LOG_NOTICE, SLA_EVENT_RELOAD, sla_load_config(), and sla_queue_event().

Referenced by load_module(), and reload().

05873 {
05874    load_config_meetme();
05875 
05876    if (reload) {
05877       sla_queue_event(SLA_EVENT_RELOAD);
05878       ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
05879          "and will be completed when the system is idle.\n");
05880       return 0;
05881    }
05882    
05883    return sla_load_config(0);
05884 }

static void load_config_meetme ( void   )  [static]

Definition at line 3912 of file app_meetme.c.

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

Referenced by load_config().

03913 {
03914    struct ast_config *cfg;
03915    struct ast_flags config_flags = { 0 };
03916    const char *val;
03917 
03918    if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags)))
03919       return;
03920 
03921    audio_buffers = DEFAULT_AUDIO_BUFFERS;
03922 
03923    /*  Scheduling support is off by default */
03924    rt_schedule = 0;
03925    fuzzystart = 0;
03926    earlyalert = 0;
03927    endalert = 0;
03928 
03929    /*  Logging of participants defaults to ON for compatibility reasons */
03930    rt_log_members = 1;  
03931 
03932    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03933       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
03934          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03935          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03936       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
03937          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03938             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
03939          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03940       }
03941       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03942          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03943    }
03944 
03945    if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
03946       rt_schedule = ast_true(val);
03947    if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
03948       rt_log_members = ast_true(val);
03949    if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
03950       if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
03951          ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
03952          fuzzystart = 0;
03953       } 
03954    }
03955    if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
03956       if ((sscanf(val, "%30d", &earlyalert) != 1)) {
03957          ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
03958          earlyalert = 0;
03959       } 
03960    }
03961    if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
03962       if ((sscanf(val, "%30d", &endalert) != 1)) {
03963          ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
03964          endalert = 0;
03965       } 
03966    }
03967 
03968    ast_config_destroy(cfg);
03969 }

static int load_module ( void   )  [static]

Definition at line 5912 of file app_meetme.c.

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

05913 {
05914    int res = 0;
05915 
05916    res |= load_config(0);
05917 
05918    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05919    res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 
05920                 action_meetmemute, "Mute a Meetme user");
05921    res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 
05922                 action_meetmeunmute, "Unmute a Meetme user");
05923    res |= ast_manager_register2("MeetmeList", EVENT_FLAG_REPORTING, 
05924                 action_meetmelist, "List participants in a conference", mandescr_meetmelist);
05925    res |= ast_register_application(app4, channel_admin_exec, synopsis4, descrip4);
05926    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
05927    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
05928    res |= ast_register_application(app, conf_exec, synopsis, descrip);
05929    res |= ast_register_application(slastation_app, sla_station_exec,
05930                slastation_synopsis, slastation_desc);
05931    res |= ast_register_application(slatrunk_app, sla_trunk_exec,
05932                slatrunk_synopsis, slatrunk_desc);
05933 
05934    res |= ast_devstate_prov_add("Meetme", meetmestate);
05935    res |= ast_devstate_prov_add("SLA", sla_state);
05936 
05937    res |= ast_custom_function_register(&meetme_info_acf);
05938    ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
05939 
05940    return res;
05941 }

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

Definition at line 981 of file app_meetme.c.

References admin_exec(), ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_debug, ast_free, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_str_append(), ast_str_create(), ast_str_set(), ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd(), CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_cli_args::fd, ast_conference::isdynamic, istalking(), ast_conf_user::jointime, ast_cli_args::line, ast_conference::locked, ast_conference::markedusers, MAX_CONFNUM, MC_DATA_FORMAT, MC_HEADER_FORMAT, ast_cli_args::n, ast_cli_args::pos, S_OR, sec, ast_conference::start, ast_str::str, ast_conf_user::talking, total, ast_cli_entry::usage, ast_conf_user::user_no, ast_conf_user::userflags, ast_conference::userlist, ast_conference::users, and ast_cli_args::word.

00982 {
00983    /* Process the command */
00984    struct ast_conference *cnf;
00985    struct ast_conf_user *user;
00986    int hr, min, sec;
00987    int i = 0, total = 0;
00988    time_t now;
00989    struct ast_str *cmdline = NULL;
00990 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s  %-8s  %-6s\n"
00991 #define MC_DATA_FORMAT "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s  %-6s\n"
00992 
00993    switch (cmd) {
00994    case CLI_INIT:
00995       e->command = "meetme";
00996       e->usage =
00997          "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
00998          "       Executes a command for the conference or on a conferee\n";
00999       return NULL;
01000    case CLI_GENERATE:
01001       return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01002    }
01003 
01004    if (a->argc > 8)
01005       ast_cli(a->fd, "Invalid Arguments.\n");
01006    /* Check for length so no buffer will overflow... */
01007    for (i = 0; i < a->argc; i++) {
01008       if (strlen(a->argv[i]) > 100)
01009          ast_cli(a->fd, "Invalid Arguments.\n");
01010    }
01011 
01012    /* Max confno length */
01013    if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01014       return CLI_FAILURE;
01015    }
01016 
01017    if (a->argc == 1 || (a->argc == 2 && !strcasecmp(a->argv[1], "concise"))) {
01018       /* 'MeetMe': List all the conferences */  
01019       int concise = (a->argc == 2 && !strcasecmp(a->argv[1], "concise"));
01020       now = time(NULL);
01021       AST_LIST_LOCK(&confs);
01022       if (AST_LIST_EMPTY(&confs)) {
01023          if (!concise) {
01024             ast_cli(a->fd, "No active MeetMe conferences.\n");
01025          }
01026          AST_LIST_UNLOCK(&confs);
01027          ast_free(cmdline);
01028          return CLI_SUCCESS;
01029       }
01030       if (!concise) {
01031          ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
01032       }
01033       AST_LIST_TRAVERSE(&confs, cnf, list) {
01034          if (cnf->markedusers == 0) {
01035             ast_str_set(&cmdline, 0, "N/A ");
01036          } else {
01037             ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
01038          }
01039          hr = (now - cnf->start) / 3600;
01040          min = ((now - cnf->start) % 3600) / 60;
01041          sec = (now - cnf->start) % 60;
01042          if (!concise) {
01043             ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, cmdline->str, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
01044          } else {
01045             ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
01046                cnf->confno,
01047                cnf->users,
01048                cnf->markedusers,
01049                hr, min, sec,
01050                cnf->isdynamic,
01051                cnf->locked);
01052          }
01053 
01054          total += cnf->users;
01055       }
01056       AST_LIST_UNLOCK(&confs);
01057       if (!concise) {
01058          ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
01059       }
01060       ast_free(cmdline);
01061       return CLI_SUCCESS;
01062    }
01063    if (a->argc < 3) {
01064       ast_free(cmdline);
01065       return CLI_SHOWUSAGE;
01066    }
01067 
01068    ast_str_set(&cmdline, 0, "%s", a->argv[2]);  /* Argv 2: conference number */
01069    if (strstr(a->argv[1], "lock")) {
01070       if (strcmp(a->argv[1], "lock") == 0) {
01071          /* Lock */
01072          ast_str_append(&cmdline, 0, ",L");
01073       } else {
01074          /* Unlock */
01075          ast_str_append(&cmdline, 0, ",l");
01076       }
01077    } else if (strstr(a->argv[1], "mute")) { 
01078       if (a->argc < 4) {
01079          ast_free(cmdline);
01080          return CLI_SHOWUSAGE;
01081       }
01082       if (strcmp(a->argv[1], "mute") == 0) {
01083          /* Mute */
01084          if (strcmp(a->argv[3], "all") == 0) {
01085             ast_str_append(&cmdline, 0, ",N");
01086          } else {
01087             ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);  
01088          }
01089       } else {
01090          /* Unmute */
01091          if (strcmp(a->argv[3], "all") == 0) {
01092             ast_str_append(&cmdline, 0, ",n");
01093          } else {
01094             ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
01095          }
01096       }
01097    } else if (strcmp(a->argv[1], "kick") == 0) {
01098       if (a->argc < 4) {
01099          ast_free(cmdline);
01100          return CLI_SHOWUSAGE;
01101       }
01102       if (strcmp(a->argv[3], "all") == 0) {
01103          /* Kick all */
01104          ast_str_append(&cmdline, 0, ",K");
01105       } else {
01106          /* Kick a single user */
01107          ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
01108       }
01109    } else if (strcmp(a->argv[1], "list") == 0) {
01110       int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
01111       /* List all the users in a conference */
01112       if (AST_LIST_EMPTY(&confs)) {
01113          if (!concise) {
01114             ast_cli(a->fd, "No active conferences.\n");
01115          }
01116          ast_free(cmdline);
01117          return CLI_SUCCESS;  
01118       }
01119       /* Find the right conference */
01120       AST_LIST_LOCK(&confs);
01121       AST_LIST_TRAVERSE(&confs, cnf, list) {
01122          if (strcmp(cnf->confno, a->argv[2]) == 0) {
01123             break;
01124          }
01125       }
01126       if (!cnf) {
01127          if (!concise)
01128             ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
01129          AST_LIST_UNLOCK(&confs);
01130          ast_free(cmdline);
01131          return CLI_SUCCESS;
01132       }
01133       /* Show all the users */
01134       time(&now);
01135       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
01136          hr = (now - user->jointime) / 3600;
01137          min = ((now - user->jointime) % 3600) / 60;
01138          sec = (now - user->jointime) % 60;
01139          if (!concise) {
01140             ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
01141                user->user_no,
01142                S_OR(user->chan->cid.cid_num, "<unknown>"),
01143                S_OR(user->chan->cid.cid_name, "<no name>"),
01144                user->chan->name,
01145                user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
01146                user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
01147                user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
01148                user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
01149                istalking(user->talking), hr, min, sec); 
01150          } else {
01151             ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
01152                user->user_no,
01153                S_OR(user->chan->cid.cid_num, ""),
01154                S_OR(user->chan->cid.cid_name, ""),
01155                user->chan->name,
01156                user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
01157                user->userflags  & CONFFLAG_MONITOR ? "1" : "",
01158                user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
01159                user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
01160                user->talking, hr, min, sec);
01161          }
01162       }
01163       if (!concise) {
01164          ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
01165       }
01166       AST_LIST_UNLOCK(&confs);
01167       ast_free(cmdline);
01168       return CLI_SUCCESS;
01169    } else {
01170       ast_free(cmdline);
01171       return CLI_SHOWUSAGE;
01172    }
01173 
01174    ast_debug(1, "Cmdline: %s\n", cmdline->str);
01175 
01176    admin_exec(NULL, cmdline->str);
01177    ast_free(cmdline);
01178 
01179    return CLI_SUCCESS;
01180 }

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

Definition at line 3679 of file app_meetme.c.

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

Referenced by action_meetmemute(), and action_meetmeunmute().

03680 {
03681    struct ast_conference *conf;
03682    struct ast_conf_user *user;
03683    const char *confid = astman_get_header(m, "Meetme");
03684    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
03685    int userno;
03686 
03687    if (ast_strlen_zero(confid)) {
03688       astman_send_error(s, m, "Meetme conference not specified");
03689       return 0;
03690    }
03691 
03692    if (ast_strlen_zero(userid)) {
03693       astman_send_error(s, m, "Meetme user number not specified");
03694       return 0;
03695    }
03696 
03697    userno = strtoul(userid, &userid, 10);
03698 
03699    if (*userid) {
03700       astman_send_error(s, m, "Invalid user number");
03701       return 0;
03702    }
03703 
03704    /* Look in the conference list */
03705    AST_LIST_LOCK(&confs);
03706    AST_LIST_TRAVERSE(&confs, conf, list) {
03707       if (!strcmp(confid, conf->confno))
03708          break;
03709    }
03710 
03711    if (!conf) {
03712       AST_LIST_UNLOCK(&confs);
03713       astman_send_error(s, m, "Meetme conference does not exist");
03714       return 0;
03715    }
03716 
03717    AST_LIST_TRAVERSE(&conf->userlist, user, list)
03718       if (user->user_no == userno)
03719          break;
03720 
03721    if (!user) {
03722       AST_LIST_UNLOCK(&confs);
03723       astman_send_error(s, m, "User number not found");
03724       return 0;
03725    }
03726 
03727    if (mute)
03728       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
03729    else
03730       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
03731 
03732    AST_LIST_UNLOCK(&confs);
03733 
03734    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);
03735 
03736    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
03737    return 0;
03738 }

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

Callback for devicestate providers.

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

03891 {
03892    struct ast_conference *conf;
03893 
03894    /* Find conference */
03895    AST_LIST_LOCK(&confs);
03896    AST_LIST_TRAVERSE(&confs, conf, list) {
03897       if (!strcmp(data, conf->confno))
03898          break;
03899    }
03900    AST_LIST_UNLOCK(&confs);
03901    if (!conf)
03902       return AST_DEVICE_INVALID;
03903 
03904 
03905    /* SKREP to fill */
03906    if (!conf->users)
03907       return AST_DEVICE_NOT_INUSE;
03908 
03909    return AST_DEVICE_INUSE;
03910 }

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

Definition at line 5229 of file app_meetme.c.

References ALL_TRUNK_REFS, ast_calloc, AST_LIST_INSERT_HEAD, ast_mutex_lock(), ast_mutex_unlock(), ast_tvnow(), sla_ringing_trunk::ring_begin, sla, sla_change_trunk_state(), SLA_EVENT_RINGING_TRUNK, sla_queue_event(), SLA_TRUNK_STATE_RINGING, and sla_ringing_trunk::trunk.

Referenced by sla_trunk_exec().

05230 {
05231    struct sla_ringing_trunk *ringing_trunk;
05232 
05233    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
05234       return NULL;
05235    
05236    ringing_trunk->trunk = trunk;
05237    ringing_trunk->ring_begin = ast_tvnow();
05238 
05239    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
05240 
05241    ast_mutex_lock(&sla.lock);
05242    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
05243    ast_mutex_unlock(&sla.lock);
05244 
05245    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05246 
05247    return ringing_trunk;
05248 }

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

Definition at line 3825 of file app_meetme.c.

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

03826 {
03827    struct ast_conference *cnf = args;
03828    struct ast_frame *f = NULL;
03829    int flags;
03830    struct ast_filestream *s = NULL;
03831    int res = 0;
03832    int x;
03833    const char *oldrecordingfilename = NULL;
03834 
03835    if (!cnf || !cnf->lchan) {
03836       pthread_exit(0);
03837    }
03838 
03839    ast_stopstream(cnf->lchan);
03840    flags = O_CREAT | O_TRUNC | O_WRONLY;
03841 
03842 
03843    cnf->recording = MEETME_RECORD_ACTIVE;
03844    while (ast_waitfor(cnf->lchan, -1) > -1) {
03845       if (cnf->recording == MEETME_RECORD_TERMINATE) {
03846          AST_LIST_LOCK(&confs);
03847          AST_LIST_UNLOCK(&confs);
03848          break;
03849       }
03850       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
03851          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
03852          oldrecordingfilename = cnf->recordingfilename;
03853       }
03854       
03855       f = ast_read(cnf->lchan);
03856       if (!f) {
03857          res = -1;
03858          break;
03859       }
03860       if (f->frametype == AST_FRAME_VOICE) {
03861          ast_mutex_lock(&cnf->listenlock);
03862          for (x = 0; x < AST_FRAME_BITS; x++) {
03863             /* Free any translations that have occured */
03864             if (cnf->transframe[x]) {
03865                ast_frfree(cnf->transframe[x]);
03866                cnf->transframe[x] = NULL;
03867             }
03868          }
03869          if (cnf->origframe)
03870             ast_frfree(cnf->origframe);
03871          cnf->origframe = ast_frdup(f);
03872          ast_mutex_unlock(&cnf->listenlock);
03873          if (s)
03874             res = ast_writestream(s, f);
03875          if (res) {
03876             ast_frfree(f);
03877             break;
03878          }
03879       }
03880       ast_frfree(f);
03881    }
03882    cnf->recording = MEETME_RECORD_OFF;
03883    if (s)
03884       ast_closestream(s);
03885    
03886    pthread_exit(0);
03887 }

static int reload ( void   )  [static]

Definition at line 5943 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

05944 {
05945    ast_unload_realtime("meetme");
05946    return load_config(1);
05947 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 775 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

00776 {
00777    signed char zero_volume = 0;
00778 
00779    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00780    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00781 }

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

Definition at line 4128 of file app_meetme.c.

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

Referenced by sla_handle_dial_state_event().

04129 {
04130    struct sla_station *station;
04131    struct sla_trunk_ref *trunk_ref;
04132    struct ast_str *conf_name = ast_str_create(16);
04133    struct ast_flags conf_flags = { 0 };
04134    struct ast_conference *conf;
04135 
04136    {
04137       struct run_station_args *args = data;
04138       station = args->station;
04139       trunk_ref = args->trunk_ref;
04140       ast_mutex_lock(args->cond_lock);
04141       ast_cond_signal(args->cond);
04142       ast_mutex_unlock(args->cond_lock);
04143       /* args is no longer valid here. */
04144    }
04145 
04146    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
04147    ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
04148    ast_set_flag(&conf_flags, 
04149       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04150    answer_trunk_chan(trunk_ref->chan);
04151    conf = build_conf(conf_name->str, "", "", 0, 0, 1, trunk_ref->chan);
04152    if (conf) {
04153       conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
04154       dispose_conf(conf);
04155       conf = NULL;
04156    }
04157    trunk_ref->chan = NULL;
04158    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04159       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04160       ast_str_append(&conf_name, 0, ",K");
04161       admin_exec(NULL, conf_name->str);
04162       trunk_ref->trunk->hold_stations = 0;
04163       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04164    }
04165 
04166    ast_dial_join(station->dial);
04167    ast_dial_destroy(station->dial);
04168    station->dial = NULL;
04169    ast_free(conf_name);
04170 
04171    return NULL;
04172 }

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

Definition at line 1635 of file app_meetme.c.

References ast_conference::confno, EVENT_FLAG_CALL, manager_event, and ast_conf_user::user_no.

Referenced by set_user_talking().

01636 {
01637    manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
01638          "Channel: %s\r\n"
01639          "Uniqueid: %s\r\n"
01640          "Meetme: %s\r\n"
01641          "Usernum: %d\r\n"
01642          "Status: %s\r\n",
01643          chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
01644 }

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

Definition at line 704 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

00705 {
00706    char gain_adjust;
00707 
00708    /* attempt to make the adjustment in the channel driver;
00709       if successful, don't adjust in the frame reading routine
00710    */
00711    gain_adjust = gain_map[volume + 5];
00712 
00713    return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00714 }

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

Definition at line 692 of file app_meetme.c.

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

Referenced by conf_run(), and tweak_talk_volume().

00693 {
00694    char gain_adjust;
00695 
00696    /* attempt to make the adjustment in the channel driver;
00697       if successful, don't adjust in the frame reading routine
00698    */
00699    gain_adjust = gain_map[volume + 5];
00700 
00701    return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00702 }

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

References send_talking_event(), and ast_conf_user::talking.

Referenced by conf_run().

01647 {
01648    int last_talking = user->talking;
01649    if (last_talking == talking)
01650       return;
01651 
01652    user->talking = talking;
01653 
01654    if (monitor) {
01655       /* Check if talking state changed. Take care of -1 which means unmonitored */
01656       int was_talking = (last_talking > 0);
01657       int now_talking = (talking > 0);
01658       if (was_talking != now_talking) {
01659          send_talking_event(chan, conf, user, now_talking);
01660       }
01661    }
01662 }

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

Definition at line 5575 of file app_meetme.c.

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

Referenced by sla_build_station().

05576 {
05577    struct sla_trunk *trunk;
05578    struct sla_trunk_ref *trunk_ref;
05579    struct sla_station_ref *station_ref;
05580    char *trunk_name, *options, *cur;
05581 
05582    options = ast_strdupa(var->value);
05583    trunk_name = strsep(&options, ",");
05584    
05585    AST_RWLIST_RDLOCK(&sla_trunks);
05586    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05587       if (!strcasecmp(trunk->name, trunk_name))
05588          break;
05589    }
05590 
05591    AST_RWLIST_UNLOCK(&sla_trunks);
05592    if (!trunk) {
05593       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
05594       return;
05595    }
05596    if (!(trunk_ref = create_trunk_ref(trunk)))
05597       return;
05598    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
05599 
05600    while ((cur = strsep(&options, ","))) {
05601       char *name, *value = cur;
05602       name = strsep(&value, "=");
05603       if (!strcasecmp(name, "ringtimeout")) {
05604          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
05605             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
05606                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05607             trunk_ref->ring_timeout = 0;
05608          }
05609       } else if (!strcasecmp(name, "ringdelay")) {
05610          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
05611             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
05612                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05613             trunk_ref->ring_delay = 0;
05614          }
05615       } else {
05616          ast_log(LOG_WARNING, "Invalid option '%s' for "
05617             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
05618       }
05619    }
05620 
05621    if (!(station_ref = sla_create_station_ref(station))) {
05622       ast_free(trunk_ref);
05623       return;
05624    }
05625    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
05626    AST_RWLIST_WRLOCK(&sla_trunks);
05627    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
05628    AST_RWLIST_UNLOCK(&sla_trunks);
05629    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
05630 }

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

Definition at line 5632 of file app_meetme.c.

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

Referenced by sla_load_config().

05633 {
05634    struct sla_station *station;
05635    struct ast_variable *var;
05636    const char *dev;
05637 
05638    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05639       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
05640       return -1;
05641    }
05642 
05643    if (!(station = ast_calloc(1, sizeof(*station))))
05644       return -1;
05645    if (ast_string_field_init(station, 32)) {
05646       ast_free(station);
05647       return -1;
05648    }
05649 
05650    ast_string_field_set(station, name, cat);
05651    ast_string_field_set(station, device, dev);
05652 
05653    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05654       if (!strcasecmp(var->name, "trunk"))
05655          sla_add_trunk_to_station(station, var);
05656       else if (!strcasecmp(var->name, "autocontext"))
05657          ast_string_field_set(station, autocontext, var->value);
05658       else if (!strcasecmp(var->name, "ringtimeout")) {
05659          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
05660             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
05661                var->value, station->name);
05662             station->ring_timeout = 0;
05663          }
05664       } else if (!strcasecmp(var->name, "ringdelay")) {
05665          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
05666             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
05667                var->value, station->name);
05668             station->ring_delay = 0;
05669          }
05670       } else if (!strcasecmp(var->name, "hold")) {
05671          if (!strcasecmp(var->value, "private"))
05672             station->hold_access = SLA_HOLD_PRIVATE;
05673          else if (!strcasecmp(var->value, "open"))
05674             station->hold_access = SLA_HOLD_OPEN;
05675          else {
05676             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
05677                var->value, station->name);
05678          }
05679 
05680       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05681          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05682             var->name, var->lineno, SLA_CONFIG_FILE);
05683       }
05684    }
05685 
05686    if (!ast_strlen_zero(station->autocontext)) {
05687       struct ast_context *context;
05688       struct sla_trunk_ref *trunk_ref;
05689       context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
05690       if (!context) {
05691          ast_log(LOG_ERROR, "Failed to automatically find or create "
05692             "context '%s' for SLA!\n", station->autocontext);
05693          destroy_station(station);
05694          return -1;
05695       }
05696       /* The extension for when the handset goes off-hook.
05697        * exten => station1,1,SLAStation(station1) */
05698       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
05699          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
05700          ast_log(LOG_ERROR, "Failed to automatically create extension "
05701             "for trunk '%s'!\n", station->name);
05702          destroy_station(station);
05703          return -1;
05704       }
05705       AST_RWLIST_RDLOCK(&sla_trunks);
05706       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05707          char exten[AST_MAX_EXTENSION];
05708          char hint[AST_MAX_APP];
05709          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05710          snprintf(hint, sizeof(hint), "SLA:%s", exten);
05711          /* Extension for this line button 
05712           * exten => station1_line1,1,SLAStation(station1_line1) */
05713          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
05714             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
05715             ast_log(LOG_ERROR, "Failed to automatically create extension "
05716                "for trunk '%s'!\n", station->name);
05717             destroy_station(station);
05718             return -1;
05719          }
05720          /* Hint for this line button 
05721           * exten => station1_line1,hint,SLA:station1_line1 */
05722          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
05723             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
05724             ast_log(LOG_ERROR, "Failed to automatically create hint "
05725                "for trunk '%s'!\n", station->name);
05726             destroy_station(station);
05727             return -1;
05728          }
05729       }
05730       AST_RWLIST_UNLOCK(&sla_trunks);
05731    }
05732 
05733    AST_RWLIST_WRLOCK(&sla_stations);
05734    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
05735    AST_RWLIST_UNLOCK(&sla_stations);
05736 
05737    return 0;
05738 }

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

Definition at line 5497 of file app_meetme.c.

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

Referenced by sla_load_config().

05498 {
05499    struct sla_trunk *trunk;
05500    struct ast_variable *var;
05501    const char *dev;
05502 
05503    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05504       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
05505       return -1;
05506    }
05507 
05508    if (sla_check_device(dev)) {
05509       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
05510          cat, dev);
05511       return -1;
05512    }
05513 
05514    if (!(trunk = ast_calloc(1, sizeof(*trunk))))
05515       return -1;
05516    if (ast_string_field_init(trunk, 32)) {
05517       ast_free(trunk);
05518       return -1;
05519    }
05520 
05521    ast_string_field_set(trunk, name, cat);
05522    ast_string_field_set(trunk, device, dev);
05523 
05524    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05525       if (!strcasecmp(var->name, "autocontext"))
05526          ast_string_field_set(trunk, autocontext, var->value);
05527       else if (!strcasecmp(var->name, "ringtimeout")) {
05528          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
05529             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
05530                var->value, trunk->name);
05531             trunk->ring_timeout = 0;
05532          }
05533       } else if (!strcasecmp(var->name, "barge"))
05534          trunk->barge_disabled = ast_false(var->value);
05535       else if (!strcasecmp(var->name, "hold")) {
05536          if (!strcasecmp(var->value, "private"))
05537             trunk->hold_access = SLA_HOLD_PRIVATE;
05538          else if (!strcasecmp(var->value, "open"))
05539             trunk->hold_access = SLA_HOLD_OPEN;
05540          else {
05541             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
05542                var->value, trunk->name);
05543          }
05544       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05545          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05546             var->name, var->lineno, SLA_CONFIG_FILE);
05547       }
05548    }
05549 
05550    if (!ast_strlen_zero(trunk->autocontext)) {
05551       struct ast_context *context;
05552       context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
05553       if (!context) {
05554          ast_log(LOG_ERROR, "Failed to automatically find or create "
05555             "context '%s' for SLA!\n", trunk->autocontext);
05556          destroy_trunk(trunk);
05557          return -1;
05558       }
05559       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
05560          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
05561          ast_log(LOG_ERROR, "Failed to automatically create extension "
05562             "for trunk '%s'!\n", trunk->name);
05563          destroy_trunk(trunk);
05564          return -1;
05565       }
05566    }
05567 
05568    AST_RWLIST_WRLOCK(&sla_trunks);
05569    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
05570    AST_RWLIST_UNLOCK(&sla_trunks);
05571 
05572    return 0;
05573 }

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

References AST_LIST_TRAVERSE, sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), and sla_choose_ringing_trunk().

Referenced by sla_process_timers().

04742 {
04743    struct sla_station *station;
04744    int res = 0;
04745 
04746    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04747       struct sla_ringing_trunk *ringing_trunk;
04748       int time_left;
04749 
04750       /* Ignore stations already ringing */
04751       if (sla_check_ringing_station(station))
04752          continue;
04753 
04754       /* Ignore stations already on a call */
04755       if (sla_check_inuse_station(station))
04756          continue;
04757 
04758       /* Ignore stations that don't have one of their trunks ringing */
04759       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
04760          continue;
04761 
04762       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
04763          continue;
04764 
04765       /* If there is no time left, then the station needs to start ringing.
04766        * Return non-zero so that an event will be queued up an event to 
04767        * make that happen. */
04768       if (time_left <= 0) {
04769          res = 1;
04770          continue;
04771       }
04772 
04773       if (time_left < *timeout)
04774          *timeout = time_left;
04775    }
04776 
04777    return res;
04778 }

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

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

Referenced by sla_process_timers().

04659 {
04660    struct sla_ringing_trunk *ringing_trunk;
04661    struct sla_ringing_station *ringing_station;
04662    int res = 0;
04663 
04664    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04665       unsigned int ring_timeout = 0;
04666       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
04667       struct sla_trunk_ref *trunk_ref;
04668 
04669       /* If there are any ring timeouts specified for a specific trunk
04670        * on the station, then use the highest per-trunk ring timeout.
04671        * Otherwise, use the ring timeout set for the entire station. */
04672       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04673          struct sla_station_ref *station_ref;
04674          int trunk_time_elapsed, trunk_time_left;
04675 
04676          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04677             if (ringing_trunk->trunk == trunk_ref->trunk)
04678                break;
04679          }
04680          if (!ringing_trunk)
04681             continue;
04682 
04683          /* If there is a trunk that is ringing without a timeout, then the
04684           * only timeout that could matter is a global station ring timeout. */
04685          if (!trunk_ref->ring_timeout)
04686             break;
04687 
04688          /* This trunk on this station is ringing and has a timeout.
04689           * However, make sure this trunk isn't still ringing from a
04690           * previous timeout.  If so, don't consider it. */
04691          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
04692             if (station_ref->station == ringing_station->station)
04693                break;
04694          }
04695          if (station_ref)
04696             continue;
04697 
04698          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04699          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
04700          if (trunk_time_left > final_trunk_time_left)
04701             final_trunk_time_left = trunk_time_left;
04702       }
04703 
04704       /* No timeout was found for ringing trunks, and no timeout for the entire station */
04705       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
04706          continue;
04707 
04708       /* Compute how much time is left for a global station timeout */
04709       if (ringing_station->station->ring_timeout) {
04710          ring_timeout = ringing_station->station->ring_timeout;
04711          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
04712          time_left = (ring_timeout * 1000) - time_elapsed;
04713       }
04714 
04715       /* If the time left based on the per-trunk timeouts is smaller than the
04716        * global station ring timeout, use that. */
04717       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
04718          time_left = final_trunk_time_left;
04719 
04720       /* If there is no time left, the station needs to stop ringing */
04721       if (time_left <= 0) {
04722          AST_LIST_REMOVE_CURRENT(entry);
04723          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
04724          res = 1;
04725          continue;
04726       }
04727 
04728       /* There is still some time left for this station to ring, so save that
04729        * timeout if it is the first event scheduled to occur */
04730       if (time_left < *timeout)
04731          *timeout = time_left;
04732    }
04733    AST_LIST_TRAVERSE_SAFE_END;
04734 
04735    return res;
04736 }

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

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

Referenced by sla_process_timers().

04629 {
04630    struct sla_ringing_trunk *ringing_trunk;
04631    int res = 0;
04632 
04633    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04634       int time_left, time_elapsed;
04635       if (!ringing_trunk->trunk->ring_timeout)
04636          continue;
04637       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04638       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
04639       if (time_left <= 0) {
04640          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
04641          AST_LIST_REMOVE_CURRENT(entry);
04642          sla_stop_ringing_trunk(ringing_trunk);
04643          res = 1;
04644          continue;
04645       }
04646       if (time_left < *timeout)
04647          *timeout = time_left;
04648    }
04649    AST_LIST_TRAVERSE_SAFE_END;
04650 
04651    return res;
04652 }

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

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

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

04098 {
04099    struct sla_station *station;
04100    struct sla_trunk_ref *trunk_ref;
04101 
04102    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04103       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04104          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
04105             || trunk_ref == exclude)
04106             continue;
04107          trunk_ref->state = state;
04108          ast_devstate_changed(sla_state_to_devstate(state), 
04109             "SLA:%s_%s", station->name, trunk->name);
04110          break;
04111       }
04112    }
04113 }

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

Definition at line 5484 of file app_meetme.c.

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

Referenced by sla_build_trunk().

05485 {
05486    char *tech, *tech_data;
05487 
05488    tech_data = ast_strdupa(device);
05489    tech = strsep(&tech_data, "/");
05490 
05491    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
05492       return -1;
05493 
05494    return 0;
05495 }

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

References ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_failed_station::last_try, sla, and sla_failed_station::station.

Referenced by sla_ring_stations().

04377 {
04378    struct sla_failed_station *failed_station;
04379    int res = 0;
04380 
04381    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
04382       if (station != failed_station->station)
04383          continue;
04384       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
04385          AST_LIST_REMOVE_CURRENT(entry);
04386          ast_free(failed_station);
04387          break;
04388       }
04389       res = 1;
04390    }
04391    AST_LIST_TRAVERSE_SAFE_END
04392 
04393    return res;
04394 }

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

Check to see if a station is in use.

Definition at line 4462 of file app_meetme.c.

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

Referenced by sla_calc_station_delays(), and sla_ring_stations().

04463 {
04464    struct sla_trunk_ref *trunk_ref;
04465 
04466    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04467       if (trunk_ref->chan)
04468          return 1;
04469    }
04470 
04471    return 0;
04472 }

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

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

Referenced by sla_thread().

04821 {
04822    struct sla_station *station;
04823    struct sla_trunk *trunk;
04824 
04825    ast_mutex_lock(&sla.lock);
04826 
04827    if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
04828       || !AST_LIST_EMPTY(&sla.ringing_stations)) {
04829       ast_mutex_unlock(&sla.lock);
04830       return;
04831    }
04832 
04833    AST_RWLIST_RDLOCK(&sla_stations);
04834    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
04835       if (station->ref_count)
04836          break;
04837    }
04838    AST_RWLIST_UNLOCK(&sla_stations);
04839    if (station) {
04840       ast_mutex_unlock(&sla.lock);
04841       return;
04842    }
04843 
04844    AST_RWLIST_RDLOCK(&sla_trunks);
04845    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04846       if (trunk->ref_count)
04847          break;
04848    }
04849    AST_RWLIST_UNLOCK(&sla_trunks);
04850    if (trunk) {
04851       ast_mutex_unlock(&sla.lock);
04852       return;
04853    }
04854 
04855    /* yay */
04856    sla_load_config(1);
04857    sla.reload = 0;
04858 
04859    ast_mutex_unlock(&sla.lock);
04860 }

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

References AST_LIST_TRAVERSE, sla, and sla_ringing_station::station.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

04362 {
04363    struct sla_ringing_station *ringing_station;
04364 
04365    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
04366       if (station == ringing_station->station)
04367          return 1;
04368    }
04369 
04370    return 0;
04371 }

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

04494 {
04495    struct sla_trunk_ref *trunk_ref;
04496    unsigned int delay = UINT_MAX;
04497    int time_left, time_elapsed;
04498 
04499    if (!ringing_trunk)
04500       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
04501    else
04502       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
04503 
04504    if (!ringing_trunk || !trunk_ref)
04505       return delay;
04506 
04507    /* If this station has a ring delay specific to the highest priority
04508     * ringing trunk, use that.  Otherwise, use the ring delay specified
04509     * globally for the station. */
04510    delay = trunk_ref->ring_delay;
04511    if (!delay)
04512       delay = station->ring_delay;
04513    if (!delay)
04514       return INT_MAX;
04515 
04516    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04517    time_left = (delay * 1000) - time_elapsed;
04518 
04519    return time_left;
04520 }

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

Definition at line 4001 of file app_meetme.c.

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

Referenced by sla_find_trunk_ref_byname().

04003 {
04004    struct sla_station_ref *station_ref;
04005    struct sla_trunk_ref *trunk_ref;
04006 
04007    /* For each station that has this call on hold, check for private hold. */
04008    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
04009       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
04010          if (trunk_ref->trunk != trunk || station_ref->station == station)
04011             continue;
04012          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
04013             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
04014             return 1;
04015          return 0;
04016       }
04017    }
04018 
04019    return 0;
04020 }

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

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

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

04234 {
04235    struct sla_station_ref *timed_out_station;
04236 
04237    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
04238       if (station == timed_out_station->station)
04239          return 1;
04240    }
04241 
04242    return 0;
04243 }

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

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

Definition at line 5044 of file app_meetme.c.

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

Referenced by sla_station_exec().

05045 {
05046    struct sla_trunk_ref *trunk_ref = NULL;
05047 
05048    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05049       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
05050          break;
05051    }
05052 
05053    return trunk_ref;
05054 }

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

Choose the highest priority ringing trunk for a station.

Parameters:
station the station
remove 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 4253 of file app_meetme.c.

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

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

04255 {
04256    struct sla_trunk_ref *s_trunk_ref;
04257    struct sla_ringing_trunk *ringing_trunk = NULL;
04258 
04259    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
04260       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04261          /* Make sure this is the trunk we're looking for */
04262          if (s_trunk_ref->trunk != ringing_trunk->trunk)
04263             continue;
04264 
04265          /* This trunk on the station is ringing.  But, make sure this station
04266           * didn't already time out while this trunk was ringing. */
04267          if (sla_check_timed_out_station(ringing_trunk, station))
04268             continue;
04269 
04270          if (rm)
04271             AST_LIST_REMOVE_CURRENT(entry);
04272 
04273          if (trunk_ref)
04274             *trunk_ref = s_trunk_ref;
04275 
04276          break;
04277       }
04278       AST_LIST_TRAVERSE_SAFE_END;
04279    
04280       if (ringing_trunk)
04281          break;
04282    }
04283 
04284    return ringing_trunk;
04285 }

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

Definition at line 4066 of file app_meetme.c.

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

Referenced by sla_ring_station().

04067 {
04068    struct sla_ringing_station *ringing_station;
04069 
04070    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
04071       return NULL;
04072 
04073    ringing_station->station = station;
04074    ringing_station->ring_begin = ast_tvnow();
04075 
04076    return ringing_station;
04077 }

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

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

04055 {
04056    struct sla_station_ref *station_ref;
04057 
04058    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
04059       return NULL;
04060 
04061    station_ref->station = station;
04062 
04063    return station_ref;
04064 }

static void sla_destroy ( void   )  [static]

Definition at line 5454 of file app_meetme.c.

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

Referenced by unload_module().

05455 {
05456    struct sla_trunk *trunk;
05457    struct sla_station *station;
05458 
05459    AST_RWLIST_WRLOCK(&sla_trunks);
05460    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
05461       destroy_trunk(trunk);
05462    AST_RWLIST_UNLOCK(&sla_trunks);
05463 
05464    AST_RWLIST_WRLOCK(&sla_stations);
05465    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
05466       destroy_station(station);
05467    AST_RWLIST_UNLOCK(&sla_stations);
05468 
05469    if (sla.thread != AST_PTHREADT_NULL) {
05470       ast_mutex_lock(&sla.lock);
05471       sla.stop = 1;
05472       ast_cond_signal(&sla.cond);
05473       ast_mutex_unlock(&sla.lock);
05474       pthread_join(sla.thread, NULL);
05475    }
05476 
05477    /* Drop any created contexts from the dialplan */
05478    ast_context_destroy(NULL, sla_registrar);
05479 
05480    ast_mutex_destroy(&sla.lock);
05481    ast_cond_destroy(&sla.cond);
05482 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 4224 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

04225 {
04226    sla_queue_event(SLA_EVENT_DIAL_STATE);
04227 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 3989 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, and sla_station::name.

Referenced by sla_station_exec().

03990 {
03991    struct sla_station *station = NULL;
03992 
03993    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03994       if (!strcasecmp(station->name, name))
03995          break;
03996    }
03997 
03998    return station;
03999 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 3974 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, and sla_trunk::name.

Referenced by sla_trunk_exec().

03975 {
03976    struct sla_trunk *trunk = NULL;
03977 
03978    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03979       if (!strcasecmp(trunk->name, name))
03980          break;
03981    }
03982 
03983    return trunk;
03984 }

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

Definition at line 4474 of file app_meetme.c.

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

Referenced by sla_check_station_delay().

04476 {
04477    struct sla_trunk_ref *trunk_ref = NULL;
04478 
04479    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04480       if (trunk_ref->trunk == trunk)
04481          break;
04482    }
04483 
04484    return trunk_ref;
04485 }

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

Find a trunk reference on a station by name.

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

Definition at line 4029 of file app_meetme.c.

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

Referenced by sla_station_exec().

04031 {
04032    struct sla_trunk_ref *trunk_ref = NULL;
04033 
04034    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04035       if (strcasecmp(trunk_ref->trunk->name, name))
04036          continue;
04037 
04038       if ( (trunk_ref->trunk->barge_disabled 
04039          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
04040          (trunk_ref->trunk->hold_stations 
04041          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
04042          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
04043          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
04044       {
04045          trunk_ref = NULL;
04046       }
04047 
04048       break;
04049    }
04050 
04051    return trunk_ref;
04052 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 4287 of file app_meetme.c.

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

Referenced by sla_thread().

04288 {
04289    struct sla_ringing_station *ringing_station;
04290 
04291    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04292       struct sla_trunk_ref *s_trunk_ref = NULL;
04293       struct sla_ringing_trunk *ringing_trunk = NULL;
04294       struct run_station_args args;
04295       enum ast_dial_result dial_res;
04296       pthread_t dont_care;
04297       ast_mutex_t cond_lock;
04298       ast_cond_t cond;
04299 
04300       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
04301       case AST_DIAL_RESULT_HANGUP:
04302       case AST_DIAL_RESULT_INVALID:
04303       case AST_DIAL_RESULT_FAILED:
04304       case AST_DIAL_RESULT_TIMEOUT:
04305       case AST_DIAL_RESULT_UNANSWERED:
04306          AST_LIST_REMOVE_CURRENT(entry);
04307          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
04308          break;
04309       case AST_DIAL_RESULT_ANSWERED:
04310          AST_LIST_REMOVE_CURRENT(entry);
04311          /* Find the appropriate trunk to answer. */
04312          ast_mutex_lock(&sla.lock);
04313          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
04314          ast_mutex_unlock(&sla.lock);
04315          if (!ringing_trunk) {
04316             ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
04317             break;
04318          }
04319          /* Track the channel that answered this trunk */
04320          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
04321          /* Actually answer the trunk */
04322          answer_trunk_chan(ringing_trunk->trunk->chan);
04323          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04324          /* Now, start a thread that will connect this station to the trunk.  The rest of
04325           * the code here sets up the thread and ensures that it is able to save the arguments
04326           * before they are no longer valid since they are allocated on the stack. */
04327          args.trunk_ref = s_trunk_ref;
04328          args.station = ringing_station->station;
04329          args.cond = &cond;
04330          args.cond_lock = &cond_lock;
04331          ast_free(ringing_trunk);
04332          ast_free(ringing_station);
04333          ast_mutex_init(&cond_lock);
04334          ast_cond_init(&cond, NULL);
04335          ast_mutex_lock(&cond_lock);
04336          ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
04337          ast_cond_wait(&cond, &cond_lock);
04338          ast_mutex_unlock(&cond_lock);
04339          ast_mutex_destroy(&cond_lock);
04340          ast_cond_destroy(&cond);
04341          break;
04342       case AST_DIAL_RESULT_TRYING:
04343       case AST_DIAL_RESULT_RINGING:
04344       case AST_DIAL_RESULT_PROGRESS:
04345       case AST_DIAL_RESULT_PROCEEDING:
04346          break;
04347       }
04348       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
04349          /* Queue up reprocessing ringing trunks, and then ringing stations again */
04350          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04351          sla_queue_event(SLA_EVENT_DIAL_STATE);
04352          break;
04353       }
04354    }
04355    AST_LIST_TRAVERSE_SAFE_END;
04356 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 4604 of file app_meetme.c.

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

Referenced by sla_thread().

04605 {
04606    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
04607    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
04608    ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
04609       event->station->name, event->trunk_ref->trunk->name);
04610    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
04611       INACTIVE_TRUNK_REFS, event->trunk_ref);
04612 
04613    if (event->trunk_ref->trunk->active_stations == 1) {
04614       /* The station putting it on hold is the only one on the call, so start
04615        * Music on hold to the trunk. */
04616       event->trunk_ref->trunk->on_hold = 1;
04617       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
04618    }
04619 
04620    ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
04621    event->trunk_ref->chan = NULL;
04622 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 4594 of file app_meetme.c.

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

Referenced by sla_thread().

04595 {
04596    ast_mutex_lock(&sla.lock);
04597    sla_ring_stations();
04598    ast_mutex_unlock(&sla.lock);
04599 
04600    /* Find stations that shouldn't be ringing anymore. */
04601    sla_hangup_stations();
04602 }

static void sla_hangup_stations ( void   )  [static]

Definition at line 4566 of file app_meetme.c.

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

Referenced by sla_handle_ringing_trunk_event().

04567 {
04568    struct sla_trunk_ref *trunk_ref;
04569    struct sla_ringing_station *ringing_station;
04570 
04571    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04572       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04573          struct sla_ringing_trunk *ringing_trunk;
04574          ast_mutex_lock(&sla.lock);
04575          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04576             if (trunk_ref->trunk == ringing_trunk->trunk)
04577                break;
04578          }
04579          ast_mutex_unlock(&sla.lock);
04580          if (ringing_trunk)
04581             break;
04582       }
04583       if (!trunk_ref) {
04584          AST_LIST_REMOVE_CURRENT(entry);
04585          ast_dial_join(ringing_station->station->dial);
04586          ast_dial_destroy(ringing_station->station->dial);
04587          ringing_station->station->dial = NULL;
04588          ast_free(ringing_station);
04589       }
04590    }
04591    AST_LIST_TRAVERSE_SAFE_END
04592 }

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

Definition at line 1182 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01183 {
01184    const char *hold = "Unknown";
01185 
01186    switch (hold_access) {
01187    case SLA_HOLD_OPEN:
01188       hold = "Open";
01189       break;
01190    case SLA_HOLD_PRIVATE:
01191       hold = "Private";
01192    default:
01193       break;
01194    }
01195 
01196    return hold;
01197 }

static int sla_load_config ( int  reload  )  [static]

Definition at line 5740 of file app_meetme.c.

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

Referenced by load_config(), and sla_check_reload().

05741 {
05742    struct ast_config *cfg;
05743    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
05744    const char *cat = NULL;
05745    int res = 0;
05746    const char *val;
05747 
05748    if (!reload) {
05749       ast_mutex_init(&sla.lock);
05750       ast_cond_init(&sla.cond, NULL);
05751    }
05752 
05753    if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags)))
05754       return 0; /* Treat no config as normal */
05755    else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
05756       return 0;
05757 
05758    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
05759       sla.attempt_callerid = ast_true(val);
05760 
05761    while ((cat = ast_category_browse(cfg, cat)) && !res) {
05762       const char *type;
05763       if (!strcasecmp(cat, "general"))
05764          continue;
05765       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
05766          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
05767             SLA_CONFIG_FILE);
05768          continue;
05769       }
05770       if (!strcasecmp(type, "trunk"))
05771          res = sla_build_trunk(cfg, cat);
05772       else if (!strcasecmp(type, "station"))
05773          res = sla_build_station(cfg, cat);
05774       else {
05775          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
05776             SLA_CONFIG_FILE, type);
05777       }
05778    }
05779 
05780    ast_config_destroy(cfg);
05781 
05782    if (!reload && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations)))
05783       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
05784 
05785    return res;
05786 }

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

04783 {
04784    unsigned int timeout = UINT_MAX;
04785    struct timeval wait;
04786    unsigned int change_made = 0;
04787 
04788    /* Check for ring timeouts on ringing trunks */
04789    if (sla_calc_trunk_timeouts(&timeout))
04790       change_made = 1;
04791 
04792    /* Check for ring timeouts on ringing stations */
04793    if (sla_calc_station_timeouts(&timeout))
04794       change_made = 1;
04795 
04796    /* Check for station ring delays */
04797    if (sla_calc_station_delays(&timeout))
04798       change_made = 1;
04799 
04800    /* queue reprocessing of ringing trunks */
04801    if (change_made)
04802       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
04803 
04804    /* No timeout */
04805    if (timeout == UINT_MAX)
04806       return 0;
04807 
04808    if (ts) {
04809       wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
04810       ts->tv_sec = wait.tv_sec;
04811       ts->tv_nsec = wait.tv_usec * 1000;
04812    }
04813 
04814    return 1;
04815 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]
static void sla_queue_event_conf ( enum sla_event_type  type,
struct ast_channel chan,
struct ast_conference conf 
) [static]

Queue a SLA event from the conference.

Definition at line 1491 of file app_meetme.c.

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

Referenced by conf_run().

01493 {
01494    struct sla_station *station;
01495    struct sla_trunk_ref *trunk_ref = NULL;
01496    char *trunk_name;
01497 
01498    trunk_name = ast_strdupa(conf->confno);
01499    strsep(&trunk_name, "_");
01500    if (ast_strlen_zero(trunk_name)) {
01501       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01502       return;
01503    }
01504 
01505    AST_RWLIST_RDLOCK(&sla_stations);
01506    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01507       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01508          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01509             break;
01510       }
01511       if (trunk_ref)
01512          break;
01513    }
01514    AST_RWLIST_UNLOCK(&sla_stations);
01515 
01516    if (!trunk_ref) {
01517       ast_debug(1, "Trunk not found for event!\n");
01518       return;
01519    }
01520 
01521    sla_queue_event_full(type, trunk_ref, station, 1);
01522 }

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

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

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

01455 {
01456    struct sla_event *event;
01457 
01458    if (sla.thread == AST_PTHREADT_NULL) {
01459       return;
01460    }
01461 
01462    if (!(event = ast_calloc(1, sizeof(*event))))
01463       return;
01464 
01465    event->type = type;
01466    event->trunk_ref = trunk_ref;
01467    event->station = station;
01468 
01469    if (!lock) {
01470       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01471       return;
01472    }
01473 
01474    ast_mutex_lock(&sla.lock);
01475    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01476    ast_cond_signal(&sla.cond);
01477    ast_mutex_unlock(&sla.lock);
01478 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1480 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01481 {
01482    sla_queue_event_full(type, NULL, NULL, 0);
01483 }

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

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

Referenced by sla_ring_stations().

04400 {
04401    char *tech, *tech_data;
04402    struct ast_dial *dial;
04403    struct sla_ringing_station *ringing_station;
04404    const char *cid_name = NULL, *cid_num = NULL;
04405    enum ast_dial_result res;
04406 
04407    if (!(dial = ast_dial_create()))
04408       return -1;
04409 
04410    ast_dial_set_state_callback(dial, sla_dial_state_callback);
04411    tech_data = ast_strdupa(station->device);
04412    tech = strsep(&tech_data, "/");
04413 
04414    if (ast_dial_append(dial, tech, tech_data) == -1) {
04415       ast_dial_destroy(dial);
04416       return -1;
04417    }
04418 
04419    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
04420       cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
04421       ast_free(ringing_trunk->trunk->chan->cid.cid_name);
04422       ringing_trunk->trunk->chan->cid.cid_name = NULL;
04423    }
04424    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
04425       cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
04426       ast_free(ringing_trunk->trunk->chan->cid.cid_num);
04427       ringing_trunk->trunk->chan->cid.cid_num = NULL;
04428    }
04429 
04430    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
04431    
04432    if (cid_name)
04433       ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
04434    if (cid_num)
04435       ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
04436    
04437    if (res != AST_DIAL_RESULT_TRYING) {
04438       struct sla_failed_station *failed_station;
04439       ast_dial_destroy(dial);
04440       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
04441          return -1;
04442       failed_station->station = station;
04443       failed_station->last_try = ast_tvnow();
04444       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
04445       return -1;
04446    }
04447    if (!(ringing_station = sla_create_ringing_station(station))) {
04448       ast_dial_join(dial);
04449       ast_dial_destroy(dial);
04450       return -1;
04451    }
04452 
04453    station->dial = dial;
04454 
04455    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
04456 
04457    return 0;
04458 }

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

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

Referenced by sla_handle_ringing_trunk_event().

04526 {
04527    struct sla_station_ref *station_ref;
04528    struct sla_ringing_trunk *ringing_trunk;
04529 
04530    /* Make sure that every station that uses at least one of the ringing
04531     * trunks, is ringing. */
04532    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04533       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
04534          int time_left;
04535 
04536          /* Is this station already ringing? */
04537          if (sla_check_ringing_station(station_ref->station))
04538             continue;
04539 
04540          /* Is this station already in a call? */
04541          if (sla_check_inuse_station(station_ref->station))
04542             continue;
04543 
04544          /* Did we fail to dial this station earlier?  If so, has it been
04545           * a minute since we tried? */
04546          if (sla_check_failed_station(station_ref->station))
04547             continue;
04548 
04549          /* If this station already timed out while this trunk was ringing,
04550           * do not dial it again for this ringing trunk. */
04551          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
04552             continue;
04553 
04554          /* Check for a ring delay in progress */
04555          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
04556          if (time_left != INT_MAX && time_left > 0)
04557             continue;
04558 
04559          /* It is time to make this station begin to ring.  Do it! */
04560          sla_ring_station(ringing_trunk, station_ref->station);
04561       }
04562    }
04563    /* Now, all of the stations that should be ringing, are ringing. */
04564 }

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

Definition at line 1264 of file app_meetme.c.

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

01265 {
01266    const struct sla_station *station;
01267 
01268    switch (cmd) {
01269    case CLI_INIT:
01270       e->command = "sla show stations";
01271       e->usage =
01272          "Usage: sla show stations\n"
01273          "       This will list all stations defined in sla.conf\n";
01274       return NULL;
01275    case CLI_GENERATE:
01276       return NULL;
01277    }
01278 
01279    ast_cli(a->fd, "\n" 
01280                "=============================================================\n"
01281                "=== Configured SLA Stations =================================\n"
01282                "=============================================================\n"
01283                "===\n");
01284    AST_RWLIST_RDLOCK(&sla_stations);
01285    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01286       struct sla_trunk_ref *trunk_ref;
01287       char ring_timeout[16] = "(none)";
01288       char ring_delay[16] = "(none)";
01289       if (station->ring_timeout) {
01290          snprintf(ring_timeout, sizeof(ring_timeout), 
01291             "%u", station->ring_timeout);
01292       }
01293       if (station->ring_delay) {
01294          snprintf(ring_delay, sizeof(ring_delay), 
01295             "%u", station->ring_delay);
01296       }
01297       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01298                   "=== Station Name:    %s\n"
01299                   "=== ==> Device:      %s\n"
01300                   "=== ==> AutoContext: %s\n"
01301                   "=== ==> RingTimeout: %s\n"
01302                   "=== ==> RingDelay:   %s\n"
01303                   "=== ==> HoldAccess:  %s\n"
01304                   "=== ==> Trunks ...\n",
01305                   station->name, station->device,
01306                   S_OR(station->autocontext, "(none)"), 
01307                   ring_timeout, ring_delay,
01308                   sla_hold_str(station->hold_access));
01309       AST_RWLIST_RDLOCK(&sla_trunks);
01310       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01311          if (trunk_ref->ring_timeout) {
01312             snprintf(ring_timeout, sizeof(ring_timeout),
01313                "%u", trunk_ref->ring_timeout);
01314          } else
01315             strcpy(ring_timeout, "(none)");
01316          if (trunk_ref->ring_delay) {
01317             snprintf(ring_delay, sizeof(ring_delay),
01318                "%u", trunk_ref->ring_delay);
01319          } else
01320             strcpy(ring_delay, "(none)");
01321             ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
01322                      "===       ==> State:       %s\n"
01323                      "===       ==> RingTimeout: %s\n"
01324                      "===       ==> RingDelay:   %s\n",
01325                      trunk_ref->trunk->name,
01326                      trunkstate2str(trunk_ref->state),
01327                      ring_timeout, ring_delay);
01328       }
01329       AST_RWLIST_UNLOCK(&sla_trunks);
01330       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01331                   "===\n");
01332    }
01333    AST_RWLIST_UNLOCK(&sla_stations);
01334    ast_cli(a->fd, "============================================================\n"
01335                "\n");
01336 
01337    return CLI_SUCCESS;
01338 }

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

Definition at line 1199 of file app_meetme.c.

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

01200 {
01201    const struct sla_trunk *trunk;
01202 
01203    switch (cmd) {
01204    case CLI_INIT:
01205       e->command = "sla show trunks";
01206       e->usage =
01207          "Usage: sla show trunks\n"
01208          "       This will list all trunks defined in sla.conf\n";
01209       return NULL;
01210    case CLI_GENERATE:
01211       return NULL;
01212    }
01213 
01214    ast_cli(a->fd, "\n"
01215                "=============================================================\n"
01216                "=== Configured SLA Trunks ===================================\n"
01217                "=============================================================\n"
01218                "===\n");
01219    AST_RWLIST_RDLOCK(&sla_trunks);
01220    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01221       struct sla_station_ref *station_ref;
01222       char ring_timeout[16] = "(none)";
01223       if (trunk->ring_timeout)
01224          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01225       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01226                   "=== Trunk Name:       %s\n"
01227                   "=== ==> Device:       %s\n"
01228                   "=== ==> AutoContext:  %s\n"
01229                   "=== ==> RingTimeout:  %s\n"
01230                   "=== ==> BargeAllowed: %s\n"
01231                   "=== ==> HoldAccess:   %s\n"
01232                   "=== ==> Stations ...\n",
01233                   trunk->name, trunk->device, 
01234                   S_OR(trunk->autocontext, "(none)"), 
01235                   ring_timeout,
01236                   trunk->barge_disabled ? "No" : "Yes",
01237                   sla_hold_str(trunk->hold_access));
01238       AST_RWLIST_RDLOCK(&sla_stations);
01239       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01240          ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
01241       AST_RWLIST_UNLOCK(&sla_stations);
01242       ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
01243    }
01244    AST_RWLIST_UNLOCK(&sla_trunks);
01245    ast_cli(a->fd, "=============================================================\n\n");
01246 
01247    return CLI_SUCCESS;
01248 }

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

Definition at line 5378 of file app_meetme.c.

References AST_DEVICE_INVALID, AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_strdupa, buf, LOG_ERROR, sla_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().

05379 {
05380    char *buf, *station_name, *trunk_name;
05381    struct sla_station *station;
05382    struct sla_trunk_ref *trunk_ref;
05383    enum ast_device_state res = AST_DEVICE_INVALID;
05384 
05385    trunk_name = buf = ast_strdupa(data);
05386    station_name = strsep(&trunk_name, "_");
05387 
05388    AST_RWLIST_RDLOCK(&sla_stations);
05389    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05390       if (strcasecmp(station_name, station->name))
05391          continue;
05392       AST_RWLIST_RDLOCK(&sla_trunks);
05393       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05394          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
05395             break;
05396       }
05397       if (!trunk_ref) {
05398          AST_RWLIST_UNLOCK(&sla_trunks);
05399          break;
05400       }
05401       res = sla_state_to_devstate(trunk_ref->state);
05402       AST_RWLIST_UNLOCK(&sla_trunks);
05403    }
05404    AST_RWLIST_UNLOCK(&sla_stations);
05405 
05406    if (res == AST_DEVICE_INVALID) {
05407       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
05408          trunk_name, station_name);
05409    }
05410 
05411    return res;
05412 }

static enum ast_device_state sla_state_to_devstate ( enum sla_trunk_state  state  )  [static]
static int sla_station_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 5056 of file app_meetme.c.

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

Referenced by load_module().

05057 {
05058    char *station_name, *trunk_name;
05059    struct sla_station *station;
05060    struct sla_trunk_ref *trunk_ref = NULL;
05061    char conf_name[MAX_CONFNUM];
05062    struct ast_flags conf_flags = { 0 };
05063    struct ast_conference *conf;
05064 
05065    if (ast_strlen_zero(data)) {
05066       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05067       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05068       return 0;
05069    }
05070 
05071    trunk_name = ast_strdupa(data);
05072    station_name = strsep(&trunk_name, "_");
05073 
05074    if (ast_strlen_zero(station_name)) {
05075       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05076       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05077       return 0;
05078    }
05079 
05080    AST_RWLIST_RDLOCK(&sla_stations);
05081    station = sla_find_station(station_name);
05082    if (station)
05083       ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
05084    AST_RWLIST_UNLOCK(&sla_stations);
05085 
05086    if (!station) {
05087       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
05088       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05089       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05090       return 0;
05091    }
05092 
05093    AST_RWLIST_RDLOCK(&sla_trunks);
05094    if (!ast_strlen_zero(trunk_name)) {
05095       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
05096    } else
05097       trunk_ref = sla_choose_idle_trunk(station);
05098    AST_RWLIST_UNLOCK(&sla_trunks);
05099 
05100    if (!trunk_ref) {
05101       if (ast_strlen_zero(trunk_name))
05102          ast_log(LOG_NOTICE, "No trunks available for call.\n");
05103       else {
05104          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
05105             "'%s' due to access controls.\n", trunk_name);
05106       }
05107       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05108       ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05109       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05110       return 0;
05111    }
05112 
05113    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
05114       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
05115          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05116       else {
05117          trunk_ref->state = SLA_TRUNK_STATE_UP;
05118          ast_devstate_changed(AST_DEVICE_INUSE, 
05119             "SLA:%s_%s", station->name, trunk_ref->trunk->name);
05120       }
05121    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
05122       struct sla_ringing_trunk *ringing_trunk;
05123 
05124       ast_mutex_lock(&sla.lock);
05125       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05126          if (ringing_trunk->trunk == trunk_ref->trunk) {
05127             AST_LIST_REMOVE_CURRENT(entry);
05128             break;
05129          }
05130       }
05131       AST_LIST_TRAVERSE_SAFE_END
05132       ast_mutex_unlock(&sla.lock);
05133 
05134       if (ringing_trunk) {
05135          answer_trunk_chan(ringing_trunk->trunk->chan);
05136          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05137 
05138          free(ringing_trunk);
05139 
05140          /* Queue up reprocessing ringing trunks, and then ringing stations again */
05141          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05142          sla_queue_event(SLA_EVENT_DIAL_STATE);
05143       }
05144    }
05145 
05146    trunk_ref->chan = chan;
05147 
05148    if (!trunk_ref->trunk->chan) {
05149       ast_mutex_t cond_lock;
05150       ast_cond_t cond;
05151       pthread_t dont_care;
05152       struct dial_trunk_args args = {
05153          .trunk_ref = trunk_ref,
05154          .station = station,
05155          .cond_lock = &cond_lock,
05156          .cond = &cond,
05157       };
05158       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05159       /* Create a thread to dial the trunk and dump it into the conference.
05160        * However, we want to wait until the trunk has been dialed and the
05161        * conference is created before continuing on here. */
05162       ast_autoservice_start(chan);
05163       ast_mutex_init(&cond_lock);
05164       ast_cond_init(&cond, NULL);
05165       ast_mutex_lock(&cond_lock);
05166       ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
05167       ast_cond_wait(&cond, &cond_lock);
05168       ast_mutex_unlock(&cond_lock);
05169       ast_mutex_destroy(&cond_lock);
05170       ast_cond_destroy(&cond);
05171       ast_autoservice_stop(chan);
05172       if (!trunk_ref->trunk->chan) {
05173          ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
05174          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05175          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05176          trunk_ref->chan = NULL;
05177          ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05178          sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05179          return 0;
05180       }
05181    }
05182 
05183    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
05184       trunk_ref->trunk->on_hold) {
05185       trunk_ref->trunk->on_hold = 0;
05186       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
05187       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05188    }
05189 
05190    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05191    ast_set_flag(&conf_flags, 
05192       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05193    ast_answer(chan);
05194    conf = build_conf(conf_name, "", "", 0, 0, 1, chan);
05195    if (conf) {
05196       conf_run(chan, conf, conf_flags.flags, NULL);
05197       dispose_conf(conf);
05198       conf = NULL;
05199    }
05200    trunk_ref->chan = NULL;
05201    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05202       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05203       strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
05204       admin_exec(NULL, conf_name);
05205       trunk_ref->trunk->hold_stations = 0;
05206       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05207    }
05208    
05209    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
05210 
05211    ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05212    sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05213 
05214    return 0;
05215 }

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

Definition at line 4189 of file app_meetme.c.

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

Referenced by sla_calc_station_timeouts(), and sla_handle_dial_state_event().

04191 {
04192    struct sla_ringing_trunk *ringing_trunk;
04193    struct sla_trunk_ref *trunk_ref;
04194    struct sla_station_ref *station_ref;
04195 
04196    ast_dial_join(ringing_station->station->dial);
04197    ast_dial_destroy(ringing_station->station->dial);
04198    ringing_station->station->dial = NULL;
04199 
04200    if (hangup == SLA_STATION_HANGUP_NORMAL)
04201       goto done;
04202 
04203    /* If the station is being hung up because of a timeout, then add it to the
04204     * list of timed out stations on each of the ringing trunks.  This is so
04205     * that when doing further processing to figure out which stations should be
04206     * ringing, which trunk to answer, determining timeouts, etc., we know which
04207     * ringing trunks we should ignore. */
04208    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04209       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04210          if (ringing_trunk->trunk == trunk_ref->trunk)
04211             break;
04212       }
04213       if (!trunk_ref)
04214          continue;
04215       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
04216          continue;
04217       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
04218    }
04219 
04220 done:
04221    ast_free(ringing_station);
04222 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 4174 of file app_meetme.c.

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

04175 {
04176    char buf[80];
04177    struct sla_station_ref *station_ref;
04178 
04179    snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
04180    admin_exec(NULL, buf);
04181    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04182 
04183    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
04184       ast_free(station_ref);
04185 
04186    ast_free(ringing_trunk);
04187 }

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

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

04863 {
04864    struct sla_failed_station *failed_station;
04865    struct sla_ringing_station *ringing_station;
04866 
04867    ast_mutex_lock(&sla.lock);
04868 
04869    while (!sla.stop) {
04870       struct sla_event *event;
04871       struct timespec ts = { 0, };
04872       unsigned int have_timeout = 0;
04873 
04874       if (AST_LIST_EMPTY(&sla.event_q)) {
04875          if ((have_timeout = sla_process_timers(&ts)))
04876             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
04877          else
04878             ast_cond_wait(&sla.cond, &sla.lock);
04879          if (sla.stop)
04880             break;
04881       }
04882 
04883       if (have_timeout)
04884          sla_process_timers(NULL);
04885 
04886       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
04887          ast_mutex_unlock(&sla.lock);
04888          switch (event->type) {
04889          case SLA_EVENT_HOLD:
04890             sla_handle_hold_event(event);
04891             break;
04892          case SLA_EVENT_DIAL_STATE:
04893             sla_handle_dial_state_event();
04894             break;
04895          case SLA_EVENT_RINGING_TRUNK:
04896             sla_handle_ringing_trunk_event();
04897             break;
04898          case SLA_EVENT_RELOAD:
04899             sla.reload = 1;
04900          case SLA_EVENT_CHECK_RELOAD:
04901             break;
04902          }
04903          ast_free(event);
04904          ast_mutex_lock(&sla.lock);
04905       }
04906 
04907       if (sla.reload)
04908          sla_check_reload();
04909    }
04910 
04911    ast_mutex_unlock(&sla.lock);
04912 
04913    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
04914       ast_free(ringing_station);
04915 
04916    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
04917       ast_free(failed_station);
04918 
04919    return NULL;
04920 }

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

Definition at line 5263 of file app_meetme.c.

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

Referenced by load_module().

05264 {
05265    char conf_name[MAX_CONFNUM];
05266    struct ast_conference *conf;
05267    struct ast_flags conf_flags = { 0 };
05268    struct sla_trunk *trunk;
05269    struct sla_ringing_trunk *ringing_trunk;
05270    AST_DECLARE_APP_ARGS(args,
05271       AST_APP_ARG(trunk_name);
05272       AST_APP_ARG(options);
05273    );
05274    char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
05275    char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
05276    struct ast_flags opt_flags = { 0 };
05277    char *parse;
05278 
05279    if (ast_strlen_zero(data)) {
05280       ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
05281       return -1;
05282    }
05283 
05284    parse = ast_strdupa(data);
05285    AST_STANDARD_APP_ARGS(args, parse);
05286    if (args.argc == 2) {
05287       if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
05288          ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
05289          return -1;
05290       }
05291    }
05292 
05293    AST_RWLIST_RDLOCK(&sla_trunks);
05294    trunk = sla_find_trunk(args.trunk_name);
05295    if (trunk)
05296       ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
05297    AST_RWLIST_UNLOCK(&sla_trunks);
05298 
05299    if (!trunk) {
05300       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
05301       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05302       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05303       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05304       return 0;
05305    }
05306 
05307    if (trunk->chan) {
05308       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
05309          args.trunk_name);
05310       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05311       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05312       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05313       return 0;
05314    }
05315 
05316    trunk->chan = chan;
05317 
05318    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
05319       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05320       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05321       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05322       return 0;
05323    }
05324 
05325    snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
05326    conf = build_conf(conf_name, "", "", 1, 1, 1, chan);
05327    if (!conf) {
05328       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05329       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05330       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05331       return 0;
05332    }
05333    ast_set_flag(&conf_flags, 
05334       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
05335 
05336    if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
05337       ast_indicate(chan, -1);
05338       ast_set_flag(&conf_flags, CONFFLAG_MOH);
05339       conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
05340    } else
05341       ast_indicate(chan, AST_CONTROL_RINGING);
05342 
05343    conf_run(chan, conf, conf_flags.flags, opts);
05344    dispose_conf(conf);
05345    conf = NULL;
05346    trunk->chan = NULL;
05347    trunk->on_hold = 0;
05348 
05349    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05350 
05351    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
05352       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
05353 
05354    /* Remove the entry from the list of ringing trunks if it is still there. */
05355    ast_mutex_lock(&sla.lock);
05356    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05357       if (ringing_trunk->trunk == trunk) {
05358          AST_LIST_REMOVE_CURRENT(entry);
05359          break;
05360       }
05361    }
05362    AST_LIST_TRAVERSE_SAFE_END;
05363    ast_mutex_unlock(&sla.lock);
05364    if (ringing_trunk) {
05365       ast_free(ringing_trunk);
05366       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
05367       /* Queue reprocessing of ringing trunks to make stations stop ringing
05368        * that shouldn't be ringing after this trunk stopped. */
05369       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05370    }
05371 
05372    ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05373    sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05374 
05375    return 0;
05376 }

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

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

01251 {
01252 #define S(e) case e: return # e;
01253    switch (state) {
01254    S(SLA_TRUNK_STATE_IDLE)
01255    S(SLA_TRUNK_STATE_RINGING)
01256    S(SLA_TRUNK_STATE_UP)
01257    S(SLA_TRUNK_STATE_ONHOLD)
01258    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01259    }
01260    return "Uknown State";
01261 #undef S
01262 }

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

Definition at line 763 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

00764 {
00765    tweak_volume(&user->listen, action);
00766    /* attempt to make the adjustment in the channel driver;
00767       if successful, don't adjust in the frame reading routine
00768    */
00769    if (!set_listen_volume(user, user->listen.desired))
00770       user->listen.actual = 0;
00771    else
00772       user->listen.actual = user->listen.desired;
00773 }

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

Definition at line 751 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

00752 {
00753    tweak_volume(&user->talk, action);
00754    /* attempt to make the adjustment in the channel driver;
00755       if successful, don't adjust in the frame reading routine
00756    */
00757    if (!set_talk_volume(user, user->talk.desired))
00758       user->talk.actual = 0;
00759    else
00760       user->talk.actual = user->talk.desired;
00761 }

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

Definition at line 716 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

00717 {
00718    switch (action) {
00719    case VOL_UP:
00720       switch (vol->desired) { 
00721       case 5:
00722          break;
00723       case 0:
00724          vol->desired = 2;
00725          break;
00726       case -2:
00727          vol->desired = 0;
00728          break;
00729       default:
00730          vol->desired++;
00731          break;
00732       }
00733       break;
00734    case VOL_DOWN:
00735       switch (vol->desired) {
00736       case -5:
00737          break;
00738       case 2:
00739          vol->desired = 0;
00740          break;
00741       case 0:
00742          vol->desired = -2;
00743          break;
00744       default:
00745          vol->desired--;
00746          break;
00747       }
00748    }
00749 }

static int unload_module ( void   )  [static]

Definition at line 5886 of file app_meetme.c.

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

05887 {
05888    int res = 0;
05889    
05890    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05891    res = ast_manager_unregister("MeetmeMute");
05892    res |= ast_manager_unregister("MeetmeUnmute");
05893    res |= ast_manager_unregister("MeetmeList");
05894    res |= ast_unregister_application(app4);
05895    res |= ast_unregister_application(app3);
05896    res |= ast_unregister_application(app2);
05897    res |= ast_unregister_application(app);
05898    res |= ast_unregister_application(slastation_app);
05899    res |= ast_unregister_application(slatrunk_app);
05900 
05901    ast_devstate_prov_del("Meetme");
05902    ast_devstate_prov_del("SLA");
05903    
05904    sla_destroy();
05905    
05906    res |= ast_custom_function_unregister(&meetme_info_acf);
05907    ast_unload_realtime("meetme");
05908 
05909    return res;
05910 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 5953 of file app_meetme.c.

const char* app = "MeetMe" [static]

Definition at line 209 of file app_meetme.c.

const char* app2 = "MeetMeCount" [static]

Definition at line 210 of file app_meetme.c.

const char* app3 = "MeetMeAdmin" [static]

Definition at line 211 of file app_meetme.c.

const char* app4 = "MeetMeChannelAdmin" [static]

Definition at line 212 of file app_meetme.c.

Definition at line 5953 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 620 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 629 of file app_meetme.c.

struct ast_cli_entry cli_meetme[] [static]
Initial value:
 {
   AST_CLI_DEFINE(meetme_cmd, "Execute a command on a conference or conferee"),
   AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
   AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
}

Definition at line 1340 of file app_meetme.c.

Definition at line 611 of file app_meetme.c.

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

Definition at line 422 of file app_meetme.c.

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

const char* descrip [static]

Definition at line 232 of file app_meetme.c.

const char* descrip2 [static]

Definition at line 295 of file app_meetme.c.

const char* descrip3 [static]

Definition at line 303 of file app_meetme.c.

const char* descrip4 [static]

Definition at line 326 of file app_meetme.c.

int earlyalert [static]

Definition at line 226 of file app_meetme.c.

int endalert [static]

Definition at line 227 of file app_meetme.c.

struct { ... } event_q
struct { ... } failed_stations
struct sla_event* first [read]
int fuzzystart [static]

Definition at line 225 of file app_meetme.c.

char const gain_map[] [static]

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

Definition at line 637 of file app_meetme.c.

struct sla_event* last [read]

Definition at line 612 of file app_meetme.c.

char mandescr_meetmelist[] [static]

Definition at line 3750 of file app_meetme.c.

Definition at line 5857 of file app_meetme.c.

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

Definition at line 207 of file app_meetme.c.

Referenced by conf_exec().

static int reload

A reload has been requested

reload: Part of Asterisk module interface ---

Definition at line 622 of file app_meetme.c.

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

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

Definition at line 230 of file app_meetme.c.

int rt_schedule [static]

Definition at line 224 of file app_meetme.c.

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

Definition at line 5261 of file app_meetme.c.

Referenced by sla_trunk_exec().

const char* slastation_app = "SLAStation" [static]

Definition at line 213 of file app_meetme.c.

const char* slastation_desc [static]

Definition at line 334 of file app_meetme.c.

const char* slastation_synopsis = "Shared Line Appearance Station" [static]

Definition at line 220 of file app_meetme.c.

const char* slatrunk_app = "SLATrunk" [static]

Definition at line 214 of file app_meetme.c.

const char* slatrunk_desc [static]

Definition at line 347 of file app_meetme.c.

const char* slatrunk_synopsis = "Shared Line Appearance Trunk" [static]

Definition at line 221 of file app_meetme.c.

unsigned int stop

Definition at line 617 of file app_meetme.c.

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

const char* synopsis = "MeetMe conference bridge" [static]

Definition at line 216 of file app_meetme.c.

const char* synopsis2 = "MeetMe participant count" [static]

Definition at line 217 of file app_meetme.c.

const char* synopsis3 = "MeetMe conference Administration" [static]

Definition at line 218 of file app_meetme.c.

const char* synopsis4 = "MeetMe conference Administration (channel specific)" [static]

Definition at line 219 of file app_meetme.c.

pthread_t thread

The SLA thread ID

Definition at line 610 of file app_meetme.c.


Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1