Wed Aug 15 01:24:33 2007

Asterisk developer's documentation


app_meetme.c File Reference

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

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <zaptel/zaptel.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.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/options.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/astobj.h"
#include "asterisk/devicestate.h"
#include "asterisk/dial.h"
#include "asterisk/causes.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  ast_conf_user
struct  ast_conference
 The MeetMe Conference object. More...
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_trunk
struct  sla_trunk_ref
struct  volume

Defines

#define AST_FRAME_BITS   32
#define CONF_SIZE   320
#define CONFIG_FILE_NAME   "meetme.conf"
#define DEFAULT_AUDIO_BUFFERS   32
#define MAX_CONFNUM   80
#define MAX_PIN   80
#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) }
enum  {
  CONFFLAG_ADMIN = (1 << 0), CONFFLAG_MONITOR = (1 << 1), CONFFLAG_POUNDEXIT = (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)
}
enum  { OPT_ARG_WAITMARKED = 0, OPT_ARG_ARRAY_SIZE = 1 }
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 }
 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 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.
 AST_APP_OPTIONS (meetme_opts, BEGIN_OPTIONS AST_APP_OPTION('A', CONFFLAG_MARKEDUSER), AST_APP_OPTION('a', CONFFLAG_ADMIN), AST_APP_OPTION('b', CONFFLAG_AGI), AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT), AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN), AST_APP_OPTION('d', CONFFLAG_DYNAMIC), AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN), AST_APP_OPTION('e', CONFFLAG_EMPTY), AST_APP_OPTION('F', CONFFLAG_PASS_DTMF), AST_APP_OPTION('i', CONFFLAG_INTROUSER), AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW), AST_APP_OPTION('M', CONFFLAG_MOH), AST_APP_OPTION('m', CONFFLAG_STARTMUTED), AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER), AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT), AST_APP_OPTION('p', CONFFLAG_POUNDEXIT), AST_APP_OPTION('q', CONFFLAG_QUIET), AST_APP_OPTION('r', CONFFLAG_RECORDCONF), AST_APP_OPTION('s', CONFFLAG_STARMENU), AST_APP_OPTION('T', CONFFLAG_MONITORTALKER), AST_APP_OPTION('l', CONFFLAG_MONITOR), AST_APP_OPTION('t', CONFFLAG_TALKER), AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED), AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT), AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT), AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON), END_OPTIONS)
static AST_LIST_HEAD_STATIC (confs, ast_conference)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"MeetMe conference bridge",.load=load_module,.unload=unload_module,.reload=reload,)
static AST_RWLIST_HEAD_STATIC (sla_trunks, sla_trunk)
static AST_RWLIST_HEAD_STATIC (sla_stations, sla_station)
static struct
ast_conference
build_conf (char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount)
 Find or create a conference.
static int careful_write (int fd, unsigned char *data, int len, int block)
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 int count_exec (struct ast_channel *chan, void *data)
 The MeetmeCount application.
static struct
sla_trunk_ref
create_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_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 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)
static struct
ast_conf_user
find_user (struct ast_conference *conf, char *callerident)
static char * istalking (int x)
static int load_config (int reload)
static void load_config_meetme (void)
static int load_module (void)
static int meetme_cmd (int fd, int argc, char **argv)
static int meetmemute (struct mansession *s, const struct message *m, int mute)
static int meetmestate (const char *data)
 Callback for devicestate providers.
static struct
sla_ringing_trunk
queue_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 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 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 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_ref
sla_choose_idle_trunk (const struct sla_station *station)
 For a given station, choose the highest priority idle trunk.
static struct
sla_ringing_trunk
sla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int remove)
 Choose the highest priority ringing trunk for a station.
static struct
sla_ringing_station
sla_create_ringing_station (struct sla_station *station)
static struct
sla_station_ref
sla_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_station
sla_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_ref
sla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk)
static struct
sla_trunk_ref
sla_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 (void)
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 int sla_show_stations (int fd, int argc, char **argv)
static int sla_show_trunks (int fd, int argc, char **argv)
static int sla_state (const char *data)
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 const char * app = "MeetMe"
static const char * app2 = "MeetMeCount"
static const char * app3 = "MeetMeAdmin"
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 char const gain_map []
static char meetme_usage []
struct {
   ast_cond_t   cond
   ast_mutex_t   lock
   pthread_t   thread
sla
 A structure for data used by the sla thread.
static const char sla_registrar [] = "SLA"
static const char sla_show_stations_usage []
static const char sla_show_trunks_usage []
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"


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

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

#define CONF_SIZE   320

Definition at line 107 of file app_meetme.c.

Referenced by conf_run().

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 73 of file app_meetme.c.

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

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 77 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

Definition at line 315 of file app_meetme.c.

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

#define MAX_PIN   80

Definition at line 316 of file app_meetme.c.

Referenced by conf_exec().

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 86 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 85 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 74 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

Definition at line 79 of file app_meetme.c.

00079      {
00080    ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
00081    ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
00082    ADMINFLAG_KICKME =    (1 << 3)  /*!< User has been kicked */
00083 };

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_POUNDEXIT  If set asterisk will exit conference when '#' 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, treats 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  This is a SLA station. (Only for use by the SLA applications.)
CONFFLAG_SLA_TRUNK  This is a SLA trunk. (Only for use by the SLA applications.)

Definition at line 109 of file app_meetme.c.

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

anonymous enum

Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_ARRAY_SIZE 

Definition at line 166 of file app_meetme.c.

00166      {
00167    OPT_ARG_WAITMARKED = 0,
00168    OPT_ARG_ARRAY_SIZE = 1,
00169 };

enum entrance_sound

Enumerator:
ENTER 
LEAVE 

Definition at line 95 of file app_meetme.c.

00095                     {
00096    ENTER,
00097    LEAVE
00098 };

enum recording_state

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 100 of file app_meetme.c.

enum sla_event_type

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

Enumerator:
SLA_EVENT_HOLD  A station has put the call on hold
SLA_EVENT_DIAL_STATE  The state of a dial has changed
SLA_EVENT_RINGING_TRUNK  The state of a ringing trunk has changed

Definition at line 470 of file app_meetme.c.

00470                     {
00471    /*! A station has put the call on hold */
00472    SLA_EVENT_HOLD,
00473    /*! The state of a dial has changed */
00474    SLA_EVENT_DIAL_STATE,
00475    /*! The state of a ringing trunk has changed */
00476    SLA_EVENT_RINGING_TRUNK,
00477 };

enum sla_hold_access

Enumerator:
SLA_HOLD_OPEN  This means that any station can put it on hold, and any station can retrieve the call from hold.
SLA_HOLD_PRIVATE  This means that only the station that put the call on hold may retrieve it from hold.

Definition at line 384 of file app_meetme.c.

00384                      {
00385    /*! This means that any station can put it on hold, and any station
00386     * can retrieve the call from hold. */
00387    SLA_HOLD_OPEN,
00388    /*! This means that only the station that put the call on hold may
00389     * retrieve it from hold. */
00390    SLA_HOLD_PRIVATE,
00391 };

enum sla_station_hangup

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 503 of file app_meetme.c.

enum sla_trunk_state

Enumerator:
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 376 of file app_meetme.c.

enum sla_which_trunk_refs

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 371 of file app_meetme.c.

00371                           {
00372    ALL_TRUNK_REFS,
00373    INACTIVE_TRUNK_REFS,
00374 };

enum volume_action

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 90 of file app_meetme.c.

00090                    {
00091    VOL_UP,
00092    VOL_DOWN
00093 };


Function Documentation

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

Definition at line 2972 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

02973 {
02974    return meetmemute(s, m, 1);
02975 }

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

Definition at line 2977 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

02978 {
02979    return meetmemute(s, m, 0);
02980 }

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

The MeetMeadmin application.

Definition at line 2758 of file app_meetme.c.

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

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

02758                                                             {
02759    char *params;
02760    struct ast_conference *cnf;
02761    struct ast_conf_user *user = NULL;
02762    struct ast_module_user *u;
02763    AST_DECLARE_APP_ARGS(args,
02764       AST_APP_ARG(confno);
02765       AST_APP_ARG(command);
02766       AST_APP_ARG(user);
02767    );
02768 
02769    if (ast_strlen_zero(data)) {
02770       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
02771       return -1;
02772    }
02773 
02774    u = ast_module_user_add(chan);
02775 
02776    AST_LIST_LOCK(&confs);
02777    
02778    params = ast_strdupa(data);
02779    AST_STANDARD_APP_ARGS(args, params);
02780 
02781    if (!args.command) {
02782       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
02783       AST_LIST_UNLOCK(&confs);
02784       ast_module_user_remove(u);
02785       return -1;
02786    }
02787    AST_LIST_TRAVERSE(&confs, cnf, list) {
02788       if (!strcmp(cnf->confno, args.confno))
02789          break;
02790    }
02791 
02792    if (!cnf) {
02793       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
02794       AST_LIST_UNLOCK(&confs);
02795       ast_module_user_remove(u);
02796       return 0;
02797    }
02798 
02799    ast_atomic_fetchadd_int(&cnf->refcount, 1);
02800 
02801    if (args.user)
02802       user = find_user(cnf, args.user);
02803 
02804    switch (*args.command) {
02805    case 76: /* L: Lock */ 
02806       cnf->locked = 1;
02807       break;
02808    case 108: /* l: Unlock */ 
02809       cnf->locked = 0;
02810       break;
02811    case 75: /* K: kick all users */
02812       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
02813          user->adminflags |= ADMINFLAG_KICKME;
02814       break;
02815    case 101: /* e: Eject last user*/
02816       user = AST_LIST_LAST(&cnf->userlist);
02817       if (!(user->userflags & CONFFLAG_ADMIN))
02818          user->adminflags |= ADMINFLAG_KICKME;
02819       else
02820          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
02821       break;
02822    case 77: /* M: Mute */ 
02823       if (user) {
02824          user->adminflags |= ADMINFLAG_MUTED;
02825       } else
02826          ast_log(LOG_NOTICE, "Specified User not found!\n");
02827       break;
02828    case 78: /* N: Mute all (non-admin) users */
02829       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
02830          if (!(user->userflags & CONFFLAG_ADMIN))
02831             user->adminflags |= ADMINFLAG_MUTED;
02832       }
02833       break;               
02834    case 109: /* m: Unmute */ 
02835       if (user) {
02836          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02837       } else
02838          ast_log(LOG_NOTICE, "Specified User not found!\n");
02839       break;
02840    case 110: /* n: Unmute all users */
02841       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
02842          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02843       break;
02844    case 107: /* k: Kick user */ 
02845       if (user)
02846          user->adminflags |= ADMINFLAG_KICKME;
02847       else
02848          ast_log(LOG_NOTICE, "Specified User not found!\n");
02849       break;
02850    case 118: /* v: Lower all users listen volume */
02851       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
02852          tweak_listen_volume(user, VOL_DOWN);
02853       break;
02854    case 86: /* V: Raise all users listen volume */
02855       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
02856          tweak_listen_volume(user, VOL_UP);
02857       break;
02858    case 115: /* s: Lower all users speaking volume */
02859       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
02860          tweak_talk_volume(user, VOL_DOWN);
02861       break;
02862    case 83: /* S: Raise all users speaking volume */
02863       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
02864          tweak_talk_volume(user, VOL_UP);
02865       break;
02866    case 82: /* R: Reset all volume levels */
02867       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
02868          reset_volumes(user);
02869       break;
02870    case 114: /* r: Reset user's volume level */
02871       if (user)
02872          reset_volumes(user);
02873       else
02874          ast_log(LOG_NOTICE, "Specified User not found!\n");
02875       break;
02876    case 85: /* U: Raise user's listen volume */
02877       if (user)
02878          tweak_listen_volume(user, VOL_UP);
02879       else
02880          ast_log(LOG_NOTICE, "Specified User not found!\n");
02881       break;
02882    case 117: /* u: Lower user's listen volume */
02883       if (user)
02884          tweak_listen_volume(user, VOL_DOWN);
02885       else
02886          ast_log(LOG_NOTICE, "Specified User not found!\n");
02887       break;
02888    case 84: /* T: Raise user's talk volume */
02889       if (user)
02890          tweak_talk_volume(user, VOL_UP);
02891       else
02892          ast_log(LOG_NOTICE, "Specified User not found!\n");
02893       break;
02894    case 116: /* t: Lower user's talk volume */
02895       if (user) 
02896          tweak_talk_volume(user, VOL_DOWN);
02897       else 
02898          ast_log(LOG_NOTICE, "Specified User not found!\n");
02899       break;
02900    }
02901 
02902    AST_LIST_UNLOCK(&confs);
02903 
02904    dispose_conf(cnf);
02905 
02906    ast_module_user_remove(u);
02907    
02908    return 0;
02909 }

AST_APP_OPTIONS ( meetme_opts  ,
BEGIN_OPTIONS   AST_APP_OPTION('A', CONFFLAG_MARKEDUSER),
AST_APP_OPTION('a', CONFFLAG_ADMIN)  ,
AST_APP_OPTION('b', CONFFLAG_AGI)  ,
AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT)  ,
AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN)  ,
AST_APP_OPTION('d', CONFFLAG_DYNAMIC)  ,
AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN)  ,
AST_APP_OPTION('e', CONFFLAG_EMPTY)  ,
AST_APP_OPTION('F', CONFFLAG_PASS_DTMF)  ,
AST_APP_OPTION('i', CONFFLAG_INTROUSER)  ,
AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW)  ,
AST_APP_OPTION('M', CONFFLAG_MOH)  ,
AST_APP_OPTION('m', CONFFLAG_STARTMUTED)  ,
AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER)  ,
AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT)  ,
AST_APP_OPTION('p', CONFFLAG_POUNDEXIT)  ,
AST_APP_OPTION('q', CONFFLAG_QUIET)  ,
AST_APP_OPTION('r', CONFFLAG_RECORDCONF)  ,
AST_APP_OPTION('s', CONFFLAG_STARMENU)  ,
AST_APP_OPTION('T', CONFFLAG_MONITORTALKER)  ,
AST_APP_OPTION('l', CONFFLAG_MONITOR)  ,
AST_APP_OPTION('t', CONFFLAG_TALKER)  ,
AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED)  ,
AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT)  ,
AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT)  ,
AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON)  ,
END_OPTIONS   
)

static AST_LIST_HEAD_STATIC ( confs  ,
ast_conference   
) [static]

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT  ,
"MeetMe conference bridge"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

static AST_RWLIST_HEAD_STATIC ( sla_trunks  ,
sla_trunk   
) [static]

static AST_RWLIST_HEAD_STATIC ( sla_stations  ,
sla_station   
) [static]

static struct ast_conference* build_conf ( char *  confno,
char *  pin,
char *  pinadmin,
int  make,
int  dynamic,
int  refcount 
) [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
Returns:
A pointer to the conference struct, or NULL if it wasn't found and make or dynamic were not set.

Definition at line 739 of file app_meetme.c.

References ast_calloc, AST_FORMAT_SLINEAR, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), ast_request(), ast_set_read_format(), ast_set_write_format(), ast_verbose(), ast_conference::chan, conf_map, ast_conference::confno, ast_conference::fd, ast_channel::fds, free, ast_conference::isdynamic, ast_conference::listenlock, LOG_WARNING, option_verbose, ast_conference::pin, ast_conference::pinadmin, ast_conference::playlock, ast_conference::refcount, ast_conference::start, VERBOSE_PREFIX_3, and ast_conference::zapconf.

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

00740 {
00741    struct ast_conference *cnf;
00742    struct zt_confinfo ztc = { 0, };
00743    int confno_int = 0;
00744 
00745    AST_LIST_LOCK(&confs);
00746 
00747    AST_LIST_TRAVERSE(&confs, cnf, list) {
00748       if (!strcmp(confno, cnf->confno)) 
00749          break;
00750    }
00751 
00752    if (cnf || (!make && !dynamic))
00753       goto cnfout;
00754 
00755    /* Make a new one */
00756    if (!(cnf = ast_calloc(1, sizeof(*cnf))))
00757       goto cnfout;
00758 
00759    ast_mutex_init(&cnf->playlock);
00760    ast_mutex_init(&cnf->listenlock);
00761    ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00762    ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00763    ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00764 
00765    /* Setup a new zap conference */
00766    ztc.confno = -1;
00767    ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
00768    cnf->fd = open("/dev/zap/pseudo", O_RDWR);
00769    if (cnf->fd < 0 || ioctl(cnf->fd, ZT_SETCONF, &ztc)) {
00770       ast_log(LOG_WARNING, "Unable to open pseudo device\n");
00771       if (cnf->fd >= 0)
00772          close(cnf->fd);
00773       free(cnf);
00774       cnf = NULL;
00775       goto cnfout;
00776    }
00777 
00778    cnf->zapconf = ztc.confno;
00779 
00780    /* Setup a new channel for playback of audio files */
00781    cnf->chan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
00782    if (cnf->chan) {
00783       ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
00784       ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
00785       ztc.chan = 0;
00786       ztc.confno = cnf->zapconf;
00787       ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
00788       if (ioctl(cnf->chan->fds[0], ZT_SETCONF, &ztc)) {
00789          ast_log(LOG_WARNING, "Error setting conference\n");
00790          if (cnf->chan)
00791             ast_hangup(cnf->chan);
00792          else
00793             close(cnf->fd);
00794          free(cnf);
00795          cnf = NULL;
00796          goto cnfout;
00797       }
00798    }
00799 
00800    /* Fill the conference struct */
00801    cnf->start = time(NULL);
00802    cnf->isdynamic = dynamic ? 1 : 0;
00803    if (option_verbose > 2)
00804       ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
00805    AST_LIST_INSERT_HEAD(&confs, cnf, list);
00806 
00807    /* Reserve conference number in map */
00808    if ((sscanf(cnf->confno, "%d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
00809       conf_map[confno_int] = 1;
00810    
00811 cnfout:
00812    if (cnf)
00813       ast_atomic_fetchadd_int(&cnf->refcount, refcount);
00814 
00815    AST_LIST_UNLOCK(&confs);
00816 
00817    return cnf;
00818 }

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

Definition at line 574 of file app_meetme.c.

References ast_log(), and LOG_WARNING.

Referenced by conf_play(), and conf_run().

00575 {
00576    int res;
00577    int x;
00578 
00579    while (len) {
00580       if (block) {
00581          x = ZT_IOMUX_WRITE | ZT_IOMUX_SIGEVENT;
00582          res = ioctl(fd, ZT_IOMUX, &x);
00583       } else
00584          res = 0;
00585       if (res >= 0)
00586          res = write(fd, data, len);
00587       if (res < 1) {
00588          if (errno != EAGAIN) {
00589             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00590             return -1;
00591          } else
00592             return 0;
00593       }
00594       len -= res;
00595       data += res;
00596    }
00597 
00598    return 0;
00599 }

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

Definition at line 968 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, strdup, strsep(), and ast_conf_user::user_no.

00969 {
00970    static char *cmds[] = {"lock", "unlock", "mute", "unmute", "kick", "list", NULL};
00971 
00972    int len = strlen(word);
00973    int which = 0;
00974    struct ast_conference *cnf = NULL;
00975    struct ast_conf_user *usr = NULL;
00976    char *confno = NULL;
00977    char usrno[50] = "";
00978    char *myline, *ret = NULL;
00979    
00980    if (pos == 1) {      /* Command */
00981       return ast_cli_complete(word, cmds, state);
00982    } else if (pos == 2) {  /* Conference Number */
00983       AST_LIST_LOCK(&confs);
00984       AST_LIST_TRAVERSE(&confs, cnf, list) {
00985          if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
00986             ret = cnf->confno;
00987             break;
00988          }
00989       }
00990       ret = ast_strdup(ret); /* dup before releasing the lock */
00991       AST_LIST_UNLOCK(&confs);
00992       return ret;
00993    } else if (pos == 3) {
00994       /* User Number || Conf Command option*/
00995       if (strstr(line, "mute") || strstr(line, "kick")) {
00996          if (state == 0 && (strstr(line, "kick") || strstr(line,"mute")) && !strncasecmp(word, "all", len))
00997             return strdup("all");
00998          which++;
00999          AST_LIST_LOCK(&confs);
01000 
01001          /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
01002          myline = ast_strdupa(line);
01003          if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
01004             while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
01005                ;
01006          }
01007          
01008          AST_LIST_TRAVERSE(&confs, cnf, list) {
01009             if (!strcmp(confno, cnf->confno))
01010                 break;
01011          }
01012 
01013          if (cnf) {
01014             /* Search for the user */
01015             AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
01016                snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
01017                if (!strncasecmp(word, usrno, len) && ++which > state)
01018                   break;
01019             }
01020          }
01021          AST_LIST_UNLOCK(&confs);
01022          return usr ? strdup(usrno) : NULL;
01023       } else if ( strstr(line, "list") && ( 0 == state ) )
01024          return strdup("concise");
01025    }
01026 
01027    return NULL;
01028 }

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

The meetme() application.

Definition at line 2495 of file app_meetme.c.

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options(), ast_config_destroy(), ast_config_load(), AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_module_user_add, ast_module_user_remove, 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, CONFIG_FILE_NAME, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), ast_flags::flags, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, ast_variable::name, ast_variable::next, OPT_ARG_ARRAY_SIZE, ast_conference::pin, ast_conference::pinadmin, strsep(), ast_variable::value, and var.

Referenced by load_module().

02496 {
02497    int res=-1;
02498    struct ast_module_user *u;
02499    char confno[MAX_CONFNUM] = "";
02500    int allowretry = 0;
02501    int retrycnt = 0;
02502    struct ast_conference *cnf = NULL;
02503    struct ast_flags confflags = {0};
02504    int dynamic = 0;
02505    int empty = 0, empty_no_pin = 0;
02506    int always_prompt = 0;
02507    char *notdata, *info, the_pin[MAX_PIN] = "";
02508    AST_DECLARE_APP_ARGS(args,
02509       AST_APP_ARG(confno);
02510       AST_APP_ARG(options);
02511       AST_APP_ARG(pin);
02512    );
02513    char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
02514 
02515    u = ast_module_user_add(chan);
02516 
02517    if (ast_strlen_zero(data)) {
02518       allowretry = 1;
02519       notdata = "";
02520    } else {
02521       notdata = data;
02522    }
02523    
02524    if (chan->_state != AST_STATE_UP)
02525       ast_answer(chan);
02526 
02527    info = ast_strdupa(notdata);
02528 
02529    AST_STANDARD_APP_ARGS(args, info);  
02530 
02531    if (args.confno) {
02532       ast_copy_string(confno, args.confno, sizeof(confno));
02533       if (ast_strlen_zero(confno)) {
02534          allowretry = 1;
02535       }
02536    }
02537    
02538    if (args.pin)
02539       ast_copy_string(the_pin, args.pin, sizeof(the_pin));
02540 
02541    if (args.options) {
02542       ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
02543       dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
02544       if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !args.pin)
02545          strcpy(the_pin, "q");
02546 
02547       empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
02548       empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
02549       always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
02550    }
02551 
02552    do {
02553       if (retrycnt > 3)
02554          allowretry = 0;
02555       if (empty) {
02556          int i;
02557          struct ast_config *cfg;
02558          struct ast_variable *var;
02559          int confno_int;
02560 
02561          /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
02562          if ((empty_no_pin) || (!dynamic)) {
02563             cfg = ast_config_load(CONFIG_FILE_NAME);
02564             if (cfg) {
02565                var = ast_variable_browse(cfg, "rooms");
02566                while (var) {
02567                   if (!strcasecmp(var->name, "conf")) {
02568                      char *stringp = ast_strdupa(var->value);
02569                      if (stringp) {
02570                         char *confno_tmp = strsep(&stringp, "|,");
02571                         int found = 0;
02572                         if (!dynamic) {
02573                            /* For static:  run through the list and see if this conference is empty */
02574                            AST_LIST_LOCK(&confs);
02575                            AST_LIST_TRAVERSE(&confs, cnf, list) {
02576                               if (!strcmp(confno_tmp, cnf->confno)) {
02577                                  /* The conference exists, therefore it's not empty */
02578                                  found = 1;
02579                                  break;
02580                               }
02581                            }
02582                            AST_LIST_UNLOCK(&confs);
02583                            if (!found) {
02584                               /* At this point, we have a confno_tmp (static conference) that is empty */
02585                               if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
02586                                  /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
02587                                   * Case 2:  empty_no_pin and pin is blank (but not NULL)
02588                                   * Case 3:  not empty_no_pin
02589                                   */
02590                                  ast_copy_string(confno, confno_tmp, sizeof(confno));
02591                                  break;
02592                                  /* XXX the map is not complete (but we do have a confno) */
02593                               }
02594                            }
02595                         }
02596                      }
02597                   }
02598                   var = var->next;
02599                }
02600                ast_config_destroy(cfg);
02601             }
02602          }
02603 
02604          /* Select first conference number not in use */
02605          if (ast_strlen_zero(confno) && dynamic) {
02606             AST_LIST_LOCK(&confs);
02607             for (i = 0; i < sizeof(conf_map) / sizeof(conf_map[0]); i++) {
02608                if (!conf_map[i]) {
02609                   snprintf(confno, sizeof(confno), "%d", i);
02610                   conf_map[i] = 1;
02611                   break;
02612                }
02613             }
02614             AST_LIST_UNLOCK(&confs);
02615          }
02616 
02617          /* Not found? */
02618          if (ast_strlen_zero(confno)) {
02619             res = ast_streamfile(chan, "conf-noempty", chan->language);
02620             if (!res)
02621                ast_waitstream(chan, "");
02622          } else {
02623             if (sscanf(confno, "%d", &confno_int) == 1) {
02624                res = ast_streamfile(chan, "conf-enteringno", chan->language);
02625                if (!res) {
02626                   ast_waitstream(chan, "");
02627                   res = ast_say_digits(chan, confno_int, "", chan->language);
02628                }
02629             } else {
02630                ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
02631             }
02632          }
02633       }
02634 
02635       while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
02636          /* Prompt user for conference number */
02637          res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
02638          if (res < 0) {
02639             /* Don't try to validate when we catch an error */
02640             confno[0] = '\0';
02641             allowretry = 0;
02642             break;
02643          }
02644       }
02645       if (!ast_strlen_zero(confno)) {
02646          /* Check the validity of the conference */
02647          cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
02648             sizeof(the_pin), 1, &confflags);
02649          if (!cnf) {
02650             cnf = find_conf_realtime(chan, confno, 1, dynamic, 
02651                the_pin, sizeof(the_pin), 1, &confflags);
02652          }
02653 
02654          if (!cnf) {
02655             res = ast_streamfile(chan, "conf-invalid", chan->language);
02656             if (!res)
02657                ast_waitstream(chan, "");
02658             res = -1;
02659             if (allowretry)
02660                confno[0] = '\0';
02661          } else {
02662             if ((!ast_strlen_zero(cnf->pin) &&
02663                  !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
02664                 (!ast_strlen_zero(cnf->pinadmin) &&
02665                  ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
02666                char pin[MAX_PIN] = "";
02667                int j;
02668 
02669                /* Allow the pin to be retried up to 3 times */
02670                for (j = 0; j < 3; j++) {
02671                   if (*the_pin && (always_prompt == 0)) {
02672                      ast_copy_string(pin, the_pin, sizeof(pin));
02673                      res = 0;
02674                   } else {
02675                      /* Prompt user for pin if pin is required */
02676                      res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
02677                   }
02678                   if (res >= 0) {
02679                      if (!strcasecmp(pin, cnf->pin) ||
02680                          (!ast_strlen_zero(cnf->pinadmin) &&
02681                           !strcasecmp(pin, cnf->pinadmin))) {
02682                         /* Pin correct */
02683                         allowretry = 0;
02684                         if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
02685                            ast_set_flag(&confflags, CONFFLAG_ADMIN);
02686                         /* Run the conference */
02687                         res = conf_run(chan, cnf, confflags.flags, optargs);
02688                         break;
02689                      } else {
02690                         /* Pin invalid */
02691                         if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
02692                            res = ast_waitstream(chan, AST_DIGIT_ANY);
02693                            ast_stopstream(chan);
02694                         }
02695                         else {
02696                            ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
02697                            break;
02698                         }
02699                         if (res < 0)
02700                            break;
02701                         pin[0] = res;
02702                         pin[1] = '\0';
02703                         res = -1;
02704                         if (allowretry)
02705                            confno[0] = '\0';
02706                      }
02707                   } else {
02708                      /* failed when getting the pin */
02709                      res = -1;
02710                      allowretry = 0;
02711                      /* see if we need to get rid of the conference */
02712                      break;
02713                   }
02714 
02715                   /* Don't retry pin with a static pin */
02716                   if (*the_pin && (always_prompt==0)) {
02717                      break;
02718                   }
02719                }
02720             } else {
02721                /* No pin required */
02722                allowretry = 0;
02723 
02724                /* Run the conference */
02725                res = conf_run(chan, cnf, confflags.flags, optargs);
02726             }
02727             dispose_conf(cnf);
02728             cnf = NULL;
02729          }
02730       }
02731    } while (allowretry);
02732 
02733    if (cnf)
02734       dispose_conf(cnf);
02735 
02736    ast_module_user_remove(u);
02737    
02738    return res;
02739 }

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

Definition at line 1194 of file app_meetme.c.

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

Referenced by conf_run().

01195 {
01196    int x;
01197 
01198    /* read any frames that may be waiting on the channel
01199       and throw them away
01200    */
01201    if (chan) {
01202       struct ast_frame *f;
01203 
01204       /* when no frames are available, this will wait
01205          for 1 millisecond maximum
01206       */
01207       while (ast_waitfor(chan, 1)) {
01208          f = ast_read(chan);
01209          if (f)
01210             ast_frfree(f);
01211          else /* channel was hung up or something else happened */
01212             break;
01213       }
01214    }
01215 
01216    /* flush any data sitting in the pseudo channel */
01217    x = ZT_FLUSH_ALL;
01218    if (ioctl(fd, ZT_FLUSH, &x))
01219       ast_log(LOG_WARNING, "Error flushing channel\n");
01220 
01221 }

static int conf_free ( struct ast_conference conf  )  [static]

Definition at line 1225 of file app_meetme.c.

References AST_FRAME_BITS, ast_frfree(), ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_translator_free_path(), ast_conference::chan, ast_conference::fd, free, ast_conference::lchan, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, ast_conference::origframe, ast_conference::transframe, and ast_conference::transpath.

Referenced by dispose_conf().

01226 {
01227    int x;
01228    
01229    AST_LIST_REMOVE(&confs, conf, list);
01230 
01231    if (conf->recording == MEETME_RECORD_ACTIVE) {
01232       conf->recording = MEETME_RECORD_TERMINATE;
01233       AST_LIST_UNLOCK(&confs);
01234       while (1) {
01235          usleep(1);
01236          AST_LIST_LOCK(&confs);
01237          if (conf->recording == MEETME_RECORD_OFF)
01238             break;
01239          AST_LIST_UNLOCK(&confs);
01240       }
01241    }
01242 
01243    for (x=0;x<AST_FRAME_BITS;x++) {
01244       if (conf->transframe[x])
01245          ast_frfree(conf->transframe[x]);
01246       if (conf->transpath[x])
01247          ast_translator_free_path(conf->transpath[x]);
01248    }
01249    if (conf->origframe)
01250       ast_frfree(conf->origframe);
01251    if (conf->lchan)
01252       ast_hangup(conf->lchan);
01253    if (conf->chan)
01254       ast_hangup(conf->chan);
01255    else
01256       close(conf->fd);
01257    
01258    free(conf);
01259 
01260    return 0;
01261 }

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

Definition at line 692 of file app_meetme.c.

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

Referenced by conf_run().

00693 {
00694    unsigned char *data;
00695    int len;
00696    int res = -1;
00697 
00698    if (!chan->_softhangup)
00699       res = ast_autoservice_start(chan);
00700 
00701    AST_LIST_LOCK(&confs);
00702 
00703    switch(sound) {
00704    case ENTER:
00705       data = enter;
00706       len = sizeof(enter);
00707       break;
00708    case LEAVE:
00709       data = leave;
00710       len = sizeof(leave);
00711       break;
00712    default:
00713       data = NULL;
00714       len = 0;
00715    }
00716    if (data) {
00717       careful_write(conf->fd, data, len, 1);
00718    }
00719 
00720    AST_LIST_UNLOCK(&confs);
00721 
00722    if (!res) 
00723       ast_autoservice_stop(chan);
00724 }

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

Definition at line 1263 of file app_meetme.c.

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

Referenced by conf_run().

01265 {
01266    struct ast_conf_user *user;
01267 
01268    AST_LIST_TRAVERSE(&conf->userlist, user, list) {
01269       if (user == sender)
01270          continue;
01271       if (ast_write(user->chan, f) < 0)
01272          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01273    }
01274 }

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

Definition at line 1363 of file app_meetme.c.

References volume::actual, ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, ast_calloc, ast_channel_setoption(), ast_check_hangup(), ast_config_AST_SPOOL_DIR, AST_CONTROL_HOLD, ast_device_state_changed(), AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_new(), ast_dsp_silence(), ast_filedelete(), ast_fileexists(), AST_FORMAT_SLINEAR, ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_frfree(), AST_FRIENDLY_OFFSET, ast_goto_if_exists(), ast_hangup(), ast_indicate(), AST_LIST_EMPTY, AST_LIST_INSERT_TAIL, AST_LIST_LAST, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, ast_read(), ast_read_noaudio(), ast_record_review(), ast_request(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_translate(), ast_translator_build_path(), ast_update_realtime(), ast_verbose(), ast_waitfor_nandfds(), ast_waitstream(), ast_write(), ast_conference::attr, careful_write(), ast_conference::chan, ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, conf_flush(), conf_play(), conf_queue_dtmf(), CONF_SIZE, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_POUNDEXIT, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_SLA_STATION, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, ast_channel::context, ast_frame::data, ast_frame::datalen, volume::desired, ENTER, EVENT_FLAG_CALL, exitcontext, f, ast_conference::fd, ast_channel::fds, ast_frame::frametype, free, ast_conf_user::jointime, ast_conference::lchan, LEAVE, ast_conf_user::listen, ast_conference::listenlock, ast_conference::locked, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, manager_event(), ast_conference::markedusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, MEETME_RECORD_OFF, ast_conf_user::namerecloc, ast_frame::offset, OPT_ARG_WAITMARKED, option_debug, ast_conference::origframe, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_conference::playlock, ast_channel::rawwriteformat, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, reset_volumes(), s, S_OR, ast_frame::samples, set_talk_volume(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_frame::subclass, ast_conf_user::talk, ast_conf_user::talking, ast_channel::tech, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_conf_user::user_no, ast_conf_user::userflags, ast_conference::users, VERBOSE_PREFIX_4, VOL_DOWN, VOL_UP, ast_conf_user::zapchannel, and ast_conference::zapconf.

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

01364 {
01365    struct ast_conf_user *user = NULL;
01366    struct ast_conf_user *usr = NULL;
01367    int fd;
01368    struct zt_confinfo ztc, ztc_empty;
01369    struct ast_frame *f;
01370    struct ast_channel *c;
01371    struct ast_frame fr;
01372    int outfd;
01373    int ms;
01374    int nfds;
01375    int res;
01376    int flags;
01377    int retryzap;
01378    int origfd;
01379    int musiconhold = 0;
01380    int firstpass = 0;
01381    int lastmarked = 0;
01382    int currentmarked = 0;
01383    int ret = -1;
01384    int x;
01385    int menu_active = 0;
01386    int using_pseudo = 0;
01387    int duration=20;
01388    int hr, min, sec;
01389    int sent_event = 0;
01390    time_t now;
01391    struct ast_dsp *dsp=NULL;
01392    struct ast_app *app;
01393    const char *agifile;
01394    const char *agifiledefault = "conf-background.agi";
01395    char meetmesecs[30] = "";
01396    char exitcontext[AST_MAX_CONTEXT] = "";
01397    char recordingtmp[AST_MAX_EXTENSION] = "";
01398    char members[10] = "";
01399    int dtmf, opt_waitmarked_timeout = 0;
01400    time_t timeout = 0;
01401    ZT_BUFFERINFO bi;
01402    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
01403    char *buf = __buf + AST_FRIENDLY_OFFSET;
01404 
01405    if (!(user = ast_calloc(1, sizeof(*user))))
01406       return ret;
01407 
01408    /* Possible timeout waiting for marked user */
01409    if ((confflags & CONFFLAG_WAITMARKED) &&
01410       !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
01411       (sscanf(optargs[OPT_ARG_WAITMARKED], "%d", &opt_waitmarked_timeout) == 1) &&
01412       (opt_waitmarked_timeout > 0)) {
01413       timeout = time(NULL) + opt_waitmarked_timeout;
01414    }
01415 
01416    if (confflags & CONFFLAG_RECORDCONF) {
01417       if (!conf->recordingfilename) {
01418          conf->recordingfilename = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE");
01419          if (!conf->recordingfilename) {
01420             snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
01421             conf->recordingfilename = ast_strdupa(recordingtmp);
01422          }
01423          conf->recordingformat = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT");
01424          if (!conf->recordingformat) {
01425             snprintf(recordingtmp, sizeof(recordingtmp), "wav");
01426             conf->recordingformat = ast_strdupa(recordingtmp);
01427          }
01428          ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n",
01429                 conf->confno, conf->recordingfilename, conf->recordingformat);
01430       }
01431    }
01432 
01433    if ((conf->recording == MEETME_RECORD_OFF) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
01434       ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
01435       ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
01436       ztc.chan = 0;
01437       ztc.confno = conf->zapconf;
01438       ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
01439       if (ioctl(conf->lchan->fds[0], ZT_SETCONF, &ztc)) {
01440          ast_log(LOG_WARNING, "Error starting listen channel\n");
01441          ast_hangup(conf->lchan);
01442          conf->lchan = NULL;
01443       } else {
01444          pthread_attr_init(&conf->attr);
01445          pthread_attr_setdetachstate(&conf->attr, PTHREAD_CREATE_DETACHED);
01446          ast_pthread_create_background(&conf->recordthread, &conf->attr, recordthread, conf);
01447          pthread_attr_destroy(&conf->attr);
01448       }
01449    }
01450 
01451    time(&user->jointime);
01452 
01453    if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
01454       /* Sorry, but this confernce is locked! */   
01455       if (!ast_streamfile(chan, "conf-locked", chan->language))
01456          ast_waitstream(chan, "");
01457       goto outrun;
01458    }
01459 
01460    if (confflags & CONFFLAG_MARKEDUSER)
01461       conf->markedusers++;
01462       
01463       ast_mutex_lock(&conf->playlock);
01464 
01465    if (AST_LIST_EMPTY(&conf->userlist))
01466       user->user_no = 1;
01467    else
01468       user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
01469 
01470    AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
01471 
01472    user->chan = chan;
01473    user->userflags = confflags;
01474    user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
01475    user->talking = -1;
01476    conf->users++;
01477    /* Update table */
01478    snprintf(members, sizeof(members), "%d", conf->users);
01479    ast_update_realtime("meetme", "confno", conf->confno, "members", members , NULL);
01480 
01481    /* This device changed state now - if this is the first user */
01482    if (conf->users == 1)
01483       ast_device_state_changed("meetme:%s", conf->confno);
01484 
01485    ast_mutex_unlock(&conf->playlock);
01486 
01487    if (confflags & CONFFLAG_EXIT_CONTEXT) {
01488       if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) 
01489          ast_copy_string(exitcontext, agifile, sizeof(exitcontext));
01490       else if (!ast_strlen_zero(chan->macrocontext)) 
01491          ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
01492       else
01493          ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
01494    }
01495 
01496    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
01497       snprintf(user->namerecloc, sizeof(user->namerecloc),
01498           "%s/meetme/meetme-username-%s-%d", ast_config_AST_SPOOL_DIR,
01499           conf->confno, user->user_no);
01500       if (confflags & CONFFLAG_INTROUSERNOREVIEW)
01501          res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, 128, 0, NULL);
01502       else
01503          res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
01504       if (res == -1)
01505          goto outrun;
01506    }
01507 
01508    if ( !(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON)) ) {
01509       if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
01510          if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
01511             ast_waitstream(chan, "");
01512       if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
01513          if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
01514             ast_waitstream(chan, "");
01515    }
01516 
01517    if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
01518       int keepplaying = 1;
01519 
01520       if (conf->users == 2) { 
01521          if (!ast_streamfile(chan,"conf-onlyone",chan->language)) {
01522             res = ast_waitstream(chan, AST_DIGIT_ANY);
01523             ast_stopstream(chan);
01524             if (res > 0)
01525                keepplaying=0;
01526             else if (res == -1)
01527                goto outrun;
01528          }
01529       } else { 
01530          if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
01531             res = ast_waitstream(chan, AST_DIGIT_ANY);
01532             ast_stopstream(chan);
01533             if (res > 0)
01534                keepplaying=0;
01535             else if (res == -1)
01536                goto outrun;
01537          }
01538          if (keepplaying) {
01539             res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
01540             if (res > 0)
01541                keepplaying=0;
01542             else if (res == -1)
01543                goto outrun;
01544          }
01545          if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
01546             res = ast_waitstream(chan, AST_DIGIT_ANY);
01547             ast_stopstream(chan);
01548             if (res > 0)
01549                keepplaying=0;
01550             else if (res == -1) 
01551                goto outrun;
01552          }
01553       }
01554    }
01555 
01556    ast_indicate(chan, -1);
01557 
01558    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
01559       ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
01560       goto outrun;
01561    }
01562 
01563    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
01564       ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
01565       goto outrun;
01566    }
01567 
01568    retryzap = strcasecmp(chan->tech->type, "Zap");
01569    user->zapchannel = !retryzap;
01570 
01571  zapretry:
01572    origfd = chan->fds[0];
01573    if (retryzap) {
01574       fd = open("/dev/zap/pseudo", O_RDWR);
01575       if (fd < 0) {
01576          ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
01577          goto outrun;
01578       }
01579       using_pseudo = 1;
01580       /* Make non-blocking */
01581       flags = fcntl(fd, F_GETFL);
01582       if (flags < 0) {
01583          ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
01584          close(fd);
01585          goto outrun;
01586       }
01587       if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
01588          ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
01589          close(fd);
01590          goto outrun;
01591       }
01592       /* Setup buffering information */
01593       memset(&bi, 0, sizeof(bi));
01594       bi.bufsize = CONF_SIZE/2;
01595       bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
01596       bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
01597       bi.numbufs = audio_buffers;
01598       if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
01599          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
01600          close(fd);
01601          goto outrun;
01602       }
01603       x = 1;
01604       if (ioctl(fd, ZT_SETLINEAR, &x)) {
01605          ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
01606          close(fd);
01607          goto outrun;
01608       }
01609       nfds = 1;
01610    } else {
01611       /* XXX Make sure we're not running on a pseudo channel XXX */
01612       fd = chan->fds[0];
01613       nfds = 0;
01614    }
01615    memset(&ztc, 0, sizeof(ztc));
01616    memset(&ztc_empty, 0, sizeof(ztc_empty));
01617    /* Check to see if we're in a conference... */
01618    ztc.chan = 0;  
01619    if (ioctl(fd, ZT_GETCONF, &ztc)) {
01620       ast_log(LOG_WARNING, "Error getting conference\n");
01621       close(fd);
01622       goto outrun;
01623    }
01624    if (ztc.confmode) {
01625       /* Whoa, already in a conference...  Retry... */
01626       if (!retryzap) {
01627          ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
01628          retryzap = 1;
01629          goto zapretry;
01630       }
01631    }
01632    memset(&ztc, 0, sizeof(ztc));
01633    /* Add us to the conference */
01634    ztc.chan = 0;  
01635    ztc.confno = conf->zapconf;
01636 
01637    ast_mutex_lock(&conf->playlock);
01638 
01639    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
01640       if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) {
01641          if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
01642             ast_waitstream(conf->chan, "");
01643          if (!ast_streamfile(conf->chan, "conf-hasjoin", chan->language))
01644             ast_waitstream(conf->chan, "");
01645       }
01646    }
01647 
01648    if (confflags & CONFFLAG_MONITOR)
01649       ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
01650    else if (confflags & CONFFLAG_TALKER)
01651       ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
01652    else 
01653       ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
01654 
01655    if (ioctl(fd, ZT_SETCONF, &ztc)) {
01656       ast_log(LOG_WARNING, "Error setting conference\n");
01657       close(fd);
01658       ast_mutex_unlock(&conf->playlock);
01659       goto outrun;
01660    }
01661    ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf);
01662 
01663    if (!sent_event) {
01664       manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
01665                "Channel: %s\r\n"
01666                "Uniqueid: %s\r\n"
01667                "Meetme: %s\r\n"
01668                "Usernum: %d\r\n",
01669                chan->name, chan->uniqueid, conf->confno, user->user_no);
01670       sent_event = 1;
01671    }
01672 
01673    if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
01674       firstpass = 1;
01675       if (!(confflags & CONFFLAG_QUIET))
01676          if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
01677             conf_play(chan, conf, ENTER);
01678    }
01679 
01680    ast_mutex_unlock(&conf->playlock);
01681 
01682    conf_flush(fd, chan);
01683 
01684    if (confflags & CONFFLAG_AGI) {
01685       /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
01686          or use default filename of conf-background.agi */
01687 
01688       agifile = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND");
01689       if (!agifile)
01690          agifile = agifiledefault;
01691 
01692       if (user->zapchannel) {
01693          /*  Set CONFMUTE mode on Zap channel to mute DTMF tones */
01694          x = 1;
01695          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01696       }
01697       /* Find a pointer to the agi app and execute the script */
01698       app = pbx_findapp("agi");
01699       if (app) {
01700          char *s = ast_strdupa(agifile);
01701          ret = pbx_exec(chan, app, s);
01702       } else {
01703          ast_log(LOG_WARNING, "Could not find application (agi)\n");
01704          ret = -2;
01705       }
01706       if (user->zapchannel) {
01707          /*  Remove CONFMUTE mode on Zap channel */
01708          x = 0;
01709          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01710       }
01711    } else {
01712       if (user->zapchannel && (confflags & CONFFLAG_STARMENU)) {
01713          /*  Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
01714          x = 1;
01715          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01716       }  
01717       if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER) && !(dsp = ast_dsp_new())) {
01718          ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
01719          res = -1;
01720       }
01721       for(;;) {
01722          int menu_was_active = 0;
01723 
01724          outfd = -1;
01725          ms = -1;
01726 
01727          if (timeout && time(NULL) >= timeout)
01728             break;
01729 
01730          /* if we have just exited from the menu, and the user had a channel-driver
01731             volume adjustment, restore it
01732          */
01733          if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
01734             set_talk_volume(user, user->listen.desired);
01735 
01736          menu_was_active = menu_active;
01737 
01738          currentmarked = conf->markedusers;
01739          if (!(confflags & CONFFLAG_QUIET) &&
01740              (confflags & CONFFLAG_MARKEDUSER) &&
01741              (confflags & CONFFLAG_WAITMARKED) &&
01742              lastmarked == 0) {
01743             if (currentmarked == 1 && conf->users > 1) {
01744                ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
01745                if (conf->users - 1 == 1) {
01746                   if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
01747                      ast_waitstream(chan, "");
01748                } else {
01749                   if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
01750                      ast_waitstream(chan, "");
01751                }
01752             }
01753             if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
01754                if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
01755                   ast_waitstream(chan, "");
01756          }
01757 
01758          c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
01759          
01760          
01761          /* Update the struct with the actual confflags */
01762          user->userflags = confflags;
01763          
01764          if (confflags & CONFFLAG_WAITMARKED) {
01765             if(currentmarked == 0) {
01766                if (lastmarked != 0) {
01767                   if (!(confflags & CONFFLAG_QUIET))
01768                      if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
01769                         ast_waitstream(chan, "");
01770                   if(confflags & CONFFLAG_MARKEDEXIT)
01771                      break;
01772                   else {
01773                      ztc.confmode = ZT_CONF_CONF;
01774                      if (ioctl(fd, ZT_SETCONF, &ztc)) {
01775                         ast_log(LOG_WARNING, "Error setting conference\n");
01776                         close(fd);
01777                         goto outrun;
01778                      }
01779                   }
01780                }
01781                if (musiconhold == 0 && (confflags & CONFFLAG_MOH)) {
01782                   ast_moh_start(chan, NULL, NULL);
01783                   musiconhold = 1;
01784                } else {
01785                   ztc.confmode = ZT_CONF_CONF;
01786                   if (ioctl(fd, ZT_SETCONF, &ztc)) {
01787                      ast_log(LOG_WARNING, "Error setting conference\n");
01788                      close(fd);
01789                      goto outrun;
01790                   }
01791                }
01792             } else if(currentmarked >= 1 && lastmarked == 0) {
01793                /* Marked user entered, so cancel timeout */
01794                timeout = 0;
01795                if (confflags & CONFFLAG_MONITOR)
01796                   ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
01797                else if (confflags & CONFFLAG_TALKER)
01798                   ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
01799                else
01800                   ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
01801                if (ioctl(fd, ZT_SETCONF, &ztc)) {
01802                   ast_log(LOG_WARNING, "Error setting conference\n");
01803                   close(fd);
01804                   goto outrun;
01805                }
01806                if (musiconhold && (confflags & CONFFLAG_MOH)) {
01807                   ast_moh_stop(chan);
01808                   musiconhold = 0;
01809                }
01810                if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
01811                   if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
01812                      ast_waitstream(chan, "");
01813                   conf_play(chan, conf, ENTER);
01814                }
01815             }
01816          }
01817 
01818          /* trying to add moh for single person conf */
01819          if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
01820             if (conf->users == 1) {
01821                if (musiconhold == 0) {
01822                   ast_moh_start(chan, NULL, NULL);
01823                   musiconhold = 1;
01824                } 
01825             } else {
01826                if (musiconhold) {
01827                   ast_moh_stop(chan);
01828                   musiconhold = 0;
01829                }
01830             }
01831          }
01832          
01833          /* Leave if the last marked user left */
01834          if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
01835             ret = -1;
01836             break;
01837          }
01838    
01839          /* Check if my modes have changed */
01840 
01841          /* If I should be muted but am still talker, mute me */
01842          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (ztc.confmode & ZT_CONF_TALKER)) {
01843             ztc.confmode ^= ZT_CONF_TALKER;
01844             if (ioctl(fd, ZT_SETCONF, &ztc)) {
01845                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01846                ret = -1;
01847                break;
01848             }
01849 
01850             manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
01851                   "Channel: %s\r\n"
01852                   "Uniqueid: %s\r\n"
01853                   "Meetme: %s\r\n"
01854                   "Usernum: %i\r\n"
01855                   "Status: on\r\n",
01856                   chan->name, chan->uniqueid, conf->confno, user->user_no);
01857          }
01858 
01859          /* If I should be un-muted but am not talker, un-mute me */
01860          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
01861             ztc.confmode |= ZT_CONF_TALKER;
01862             if (ioctl(fd, ZT_SETCONF, &ztc)) {
01863                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01864                ret = -1;
01865                break;
01866             }
01867 
01868             manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
01869                   "Channel: %s\r\n"
01870                   "Uniqueid: %s\r\n"
01871                   "Meetme: %s\r\n"
01872                   "Usernum: %i\r\n"
01873                   "Status: off\r\n",
01874                   chan->name, chan->uniqueid, conf->confno, user->user_no);
01875          }
01876 
01877          /* If I have been kicked, exit the conference */
01878          if (user->adminflags & ADMINFLAG_KICKME) {
01879             //You have been kicked.
01880             if (!(confflags & CONFFLAG_QUIET) && 
01881                !ast_streamfile(chan, "conf-kicked", chan->language)) {
01882                ast_waitstream(chan, "");
01883             }
01884             ret = 0;
01885             break;
01886          }
01887 
01888          /* Perform an extra hangup check just in case */
01889          if (ast_check_hangup(chan))
01890             break;
01891 
01892          if (c) {
01893             if (c->fds[0] != origfd) {
01894                if (using_pseudo) {
01895                   /* Kill old pseudo */
01896                   close(fd);
01897                   using_pseudo = 0;
01898                }
01899                ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
01900                retryzap = strcasecmp(c->tech->type, "Zap");
01901                user->zapchannel = !retryzap;
01902                goto zapretry;
01903             }
01904             if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
01905                f = ast_read_noaudio(c);
01906             else
01907                f = ast_read(c);
01908             if (!f)
01909                break;
01910             if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
01911                if (user->talk.actual)
01912                   ast_frame_adjust_volume(f, user->talk.actual);
01913 
01914                if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER)) {
01915                   int totalsilence;
01916 
01917                   if (user->talking == -1)
01918                      user->talking = 0;
01919 
01920                   res = ast_dsp_silence(dsp, f, &totalsilence);
01921                   if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
01922                      user->talking = 1;
01923                      if (confflags & CONFFLAG_MONITORTALKER)
01924                         manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
01925                               "Channel: %s\r\n"
01926                               "Uniqueid: %s\r\n"
01927                               "Meetme: %s\r\n"
01928                               "Usernum: %d\r\n"
01929                               "Status: on\r\n",
01930                               chan->name, chan->uniqueid, conf->confno, user->user_no);
01931                   }
01932                   if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
01933                      user->talking = 0;
01934                      if (confflags & CONFFLAG_MONITORTALKER)
01935                         manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
01936                               "Channel: %s\r\n"
01937                               "Uniqueid: %s\r\n"
01938                               "Meetme: %s\r\n"
01939                               "Usernum: %d\r\n"
01940                               "Status: off\r\n",
01941                               chan->name, chan->uniqueid, conf->confno, user->user_no);
01942                   }
01943                }
01944                if (using_pseudo) {
01945                   /* Absolutely do _not_ use careful_write here...
01946                      it is important that we read data from the channel
01947                      as fast as it arrives, and feed it into the conference.
01948                      The buffering in the pseudo channel will take care of any
01949                      timing differences, unless they are so drastic as to lose
01950                      audio frames (in which case carefully writing would only
01951                      have delayed the audio even further).
01952                   */
01953                   /* As it turns out, we do want to use careful write.  We just
01954                      don't want to block, but we do want to at least *try*
01955                      to write out all the samples.
01956                    */
01957                   if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER))
01958                      careful_write(fd, f->data, f->datalen, 0);
01959                }
01960             } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
01961                char tmp[2];
01962 
01963                tmp[0] = f->subclass;
01964                tmp[1] = '\0';
01965                if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
01966                   ast_log(LOG_DEBUG, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
01967                   ret = 0;
01968                   ast_frfree(f);
01969                   break;
01970                } else if (option_debug > 1)
01971                   ast_log(LOG_DEBUG, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp, exitcontext);
01972             } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
01973                ret = 0;
01974                ast_frfree(f);
01975                break;
01976             } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
01977                if (ioctl(fd, ZT_SETCONF, &ztc_empty)) {
01978                   ast_log(LOG_WARNING, "Error setting conference\n");
01979                   close(fd);
01980                   ast_frfree(f);
01981                   goto outrun;
01982                }
01983 
01984                /* if we are entering the menu, and the user has a channel-driver
01985                   volume adjustment, clear it
01986                */
01987                if (!menu_active && user->talk.desired && !user->talk.actual)
01988                   set_talk_volume(user, 0);
01989 
01990                if (musiconhold) {
01991                      ast_moh_stop(chan);
01992                }
01993                if ((confflags & CONFFLAG_ADMIN)) {
01994                   /* Admin menu */
01995                   if (!menu_active) {
01996                      menu_active = 1;
01997                      /* Record this sound! */
01998                      if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
01999                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02000                         ast_stopstream(chan);
02001                      } else 
02002                         dtmf = 0;
02003                   } else 
02004                      dtmf = f->subclass;
02005                   if (dtmf) {
02006                      switch(dtmf) {
02007                      case '1': /* Un/Mute */
02008                         menu_active = 0;
02009 
02010                         /* for admin, change both admin and use flags */
02011                         if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
02012                            user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02013                         else
02014                            user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02015 
02016                         if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02017                            if (!ast_streamfile(chan, "conf-muted", chan->language))
02018                               ast_waitstream(chan, "");
02019                         } else {
02020                            if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02021                               ast_waitstream(chan, "");
02022                         }
02023                         break;
02024                      case '2': /* Un/Lock the Conference */
02025                         menu_active = 0;
02026                         if (conf->locked) {
02027                            conf->locked = 0;
02028                            if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
02029                               ast_waitstream(chan, "");
02030                         } else {
02031                            conf->locked = 1;
02032                            if (!ast_streamfile(chan, "conf-lockednow", chan->language))
02033                               ast_waitstream(chan, "");
02034                         }
02035                         break;
02036                      case '3': /* Eject last user */
02037                         menu_active = 0;
02038                         usr = AST_LIST_LAST(&conf->userlist);
02039                         if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
02040                            if(!ast_streamfile(chan, "conf-errormenu", chan->language))
02041                               ast_waitstream(chan, "");
02042                         } else 
02043                            usr->adminflags |= ADMINFLAG_KICKME;
02044                         ast_stopstream(chan);
02045                         break;   
02046                      case '4':
02047                         tweak_listen_volume(user, VOL_DOWN);
02048                         break;
02049                      case '6':
02050                         tweak_listen_volume(user, VOL_UP);
02051                         break;
02052                      case '7':
02053                         tweak_talk_volume(user, VOL_DOWN);
02054                         break;
02055                      case '8':
02056                         menu_active = 0;
02057                         break;
02058                      case '9':
02059                         tweak_talk_volume(user, VOL_UP);
02060                         break;
02061                      default:
02062                         menu_active = 0;
02063                         /* Play an error message! */
02064                         if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02065                            ast_waitstream(chan, "");
02066                         break;
02067                      }
02068                   }
02069                } else {
02070                   /* User menu */
02071                   if (!menu_active) {
02072                      menu_active = 1;
02073                      if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
02074                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02075                         ast_stopstream(chan);
02076                      } else
02077                         dtmf = 0;
02078                   } else 
02079                      dtmf = f->subclass;
02080                   if (dtmf) {
02081                      switch(dtmf) {
02082                      case '1': /* Un/Mute */
02083                         menu_active = 0;
02084 
02085                         /* user can only toggle the self-muted state */
02086                         user->adminflags ^= ADMINFLAG_SELFMUTED;
02087 
02088                         /* they can't override the admin mute state */
02089                         if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02090                            if (!ast_streamfile(chan, "conf-muted", chan->language))
02091                               ast_waitstream(chan, "");
02092                         } else {
02093                            if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02094                               ast_waitstream(chan, "");
02095                         }
02096                         break;
02097                      case '4':
02098                         tweak_listen_volume(user, VOL_DOWN);
02099                         break;
02100                      case '6':
02101                         tweak_listen_volume(user, VOL_UP);
02102                         break;
02103                      case '7':
02104                         tweak_talk_volume(user, VOL_DOWN);
02105                         break;
02106                      case '8':
02107                         menu_active = 0;
02108                         break;
02109                      case '9':
02110                         tweak_talk_volume(user, VOL_UP);
02111                         break;
02112                      default:
02113                         menu_active = 0;
02114                         if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02115                            ast_waitstream(chan, "");
02116                         break;
02117                      }
02118                   }
02119                }
02120                if (musiconhold)
02121                      ast_moh_start(chan, NULL, NULL);
02122 
02123                if (ioctl(fd, ZT_SETCONF, &ztc)) {
02124                   ast_log(LOG_WARNING, "Error setting conference\n");
02125                   close(fd);
02126                   ast_frfree(f);
02127                   goto outrun;
02128                }
02129 
02130                conf_flush(fd, chan);
02131             } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
02132                && confflags & CONFFLAG_PASS_DTMF) {
02133                conf_queue_dtmf(conf, user, f);
02134             } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
02135                switch (f->subclass) {
02136                case AST_CONTROL_HOLD:
02137                   sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
02138                   break;
02139                default:
02140                   break;
02141                }
02142             } else if (f->frametype == AST_FRAME_NULL) {
02143                /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
02144             } else if (option_debug) {
02145                ast_log(LOG_DEBUG,
02146                   "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
02147                   chan->name, f->frametype, f->subclass);
02148             }
02149             ast_frfree(f);
02150          } else if (outfd > -1) {
02151             res = read(outfd, buf, CONF_SIZE);
02152             if (res > 0) {
02153                memset(&fr, 0, sizeof(fr));
02154                fr.frametype = AST_FRAME_VOICE;
02155                fr.subclass = AST_FORMAT_SLINEAR;
02156                fr.datalen = res;
02157                fr.samples = res/2;
02158                fr.data = buf;
02159                fr.offset = AST_FRIENDLY_OFFSET;
02160                if (!user->listen.actual && 
02161                   ((confflags & CONFFLAG_MONITOR) || 
02162                    (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
02163                    (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
02164                    )) {
02165                   int index;
02166                   for (index=0;index<AST_FRAME_BITS;index++)
02167                      if (chan->rawwriteformat & (1 << index))
02168                         break;
02169                   if (index >= AST_FRAME_BITS)
02170                      goto bailoutandtrynormal;
02171                   ast_mutex_lock(&conf->listenlock);
02172                   if (!conf->transframe[index]) {
02173                      if (conf->origframe) {
02174                         if (!conf->transpath[index])
02175                            conf->transpath[index] = ast_translator_build_path((1 << index), AST_FORMAT_SLINEAR);
02176                         if (conf->transpath[index]) {
02177                            conf->transframe[index] = ast_translate(conf->transpath[index], conf->origframe, 0);
02178                            if (!conf->transframe[index])
02179                               conf->transframe[index] = &ast_null_frame;
02180                         }
02181                      }
02182                   }
02183                   if (conf->transframe[index]) {
02184                      if (conf->transframe[index]->frametype != AST_FRAME_NULL) {
02185                         if (ast_write(chan, conf->transframe[index]))
02186                            ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02187                      }
02188                   } else {
02189                      ast_mutex_unlock(&conf->listenlock);
02190                      goto bailoutandtrynormal;
02191                   }
02192                   ast_mutex_unlock(&conf->listenlock);
02193                } else {
02194 bailoutandtrynormal:             
02195                   if (user->listen.actual)
02196                      ast_frame_adjust_volume(&fr, user->listen.actual);
02197                   if (ast_write(chan, &fr) < 0) {
02198                      ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02199                   }
02200                }
02201             } else 
02202                ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
02203          }
02204          lastmarked = currentmarked;
02205       }
02206    }
02207 
02208    if (musiconhold)
02209       ast_moh_stop(chan);
02210    
02211    if (using_pseudo)
02212       close(fd);
02213    else {
02214       /* Take out of conference */
02215       ztc.chan = 0;  
02216       ztc.confno = 0;
02217       ztc.confmode = 0;
02218       if (ioctl(fd, ZT_SETCONF, &ztc)) {
02219          ast_log(LOG_WARNING, "Error setting conference\n");
02220       }
02221    }
02222 
02223    reset_volumes(user);
02224 
02225    AST_LIST_LOCK(&confs);
02226    if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
02227       conf_play(chan, conf, LEAVE);
02228 
02229    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
02230       if (ast_fileexists(user->namerecloc, NULL, NULL)) {
02231          if ((conf->chan) && (conf->users > 1)) {
02232             if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
02233                ast_waitstream(conf->chan, "");
02234             if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language))
02235                ast_waitstream(conf->chan, "");
02236          }
02237          ast_filedelete(user->namerecloc, NULL);
02238       }
02239    }
02240    AST_LIST_UNLOCK(&confs);
02241 
02242  outrun:
02243    AST_LIST_LOCK(&confs);
02244 
02245    if (dsp)
02246       ast_dsp_free(dsp);
02247    
02248    if (user->user_no) { /* Only cleanup users who really joined! */
02249       now = time(NULL);
02250       hr = (now - user->jointime) / 3600;
02251       min = ((now - user->jointime) % 3600) / 60;
02252       sec = (now - user->jointime) % 60;
02253 
02254       if (sent_event) {
02255          manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
02256                   "Channel: %s\r\n"
02257                   "Uniqueid: %s\r\n"
02258                   "Meetme: %s\r\n"
02259                   "Usernum: %d\r\n"
02260                   "CallerIDnum: %s\r\n"
02261                   "CallerIDname: %s\r\n"
02262                   "Duration: %ld\r\n",
02263                   chan->name, chan->uniqueid, conf->confno, 
02264                   user->user_no,
02265                   S_OR(user->chan->cid.cid_num, "<unknown>"),
02266                   S_OR(user->chan->cid.cid_name, "<unknown>"),
02267                   (long)(now - user->jointime));
02268       }
02269 
02270       conf->users--;
02271       /* Update table */
02272       snprintf(members, sizeof(members), "%d", conf->users);
02273       ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
02274       if (confflags & CONFFLAG_MARKEDUSER) 
02275          conf->markedusers--;
02276       /* Remove ourselves from the list */
02277       AST_LIST_REMOVE(&conf->userlist, user, list);
02278 
02279       /* Change any states */
02280       if (!conf->users)
02281          ast_device_state_changed("meetme:%s", conf->confno);
02282       
02283       /* Return the number of seconds the user was in the conf */
02284       snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
02285       pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
02286    }
02287    free(user);
02288    AST_LIST_UNLOCK(&confs);
02289 
02290    return ret;
02291 }

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

The MeetmeCount application.

Definition at line 2444 of file app_meetme.c.

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

Referenced by load_module().

02445 {
02446    struct ast_module_user *u;
02447    int res = 0;
02448    struct ast_conference *conf;
02449    int count;
02450    char *localdata;
02451    char val[80] = "0"; 
02452    AST_DECLARE_APP_ARGS(args,
02453       AST_APP_ARG(confno);
02454       AST_APP_ARG(varname);
02455    );
02456 
02457    if (ast_strlen_zero(data)) {
02458       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
02459       return -1;
02460    }
02461 
02462    u = ast_module_user_add(chan);
02463    
02464    if (!(localdata = ast_strdupa(data))) {
02465       ast_module_user_remove(u);
02466       return -1;
02467    }
02468 
02469    AST_STANDARD_APP_ARGS(args, localdata);
02470    
02471    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
02472 
02473    if (conf) {
02474       count = conf->users;
02475       dispose_conf(conf);
02476       conf = NULL;
02477    } else
02478       count = 0;
02479 
02480    if (!ast_strlen_zero(args.varname)){
02481       /* have var so load it and exit */
02482       snprintf(val, sizeof(val), "%d",count);
02483       pbx_builtin_setvar_helper(chan, args.varname, val);
02484    } else {
02485       if (chan->_state != AST_STATE_UP)
02486          ast_answer(chan);
02487       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
02488    }
02489    ast_module_user_remove(u);
02490 
02491    return res;
02492 }

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

Definition at line 4239 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station().

04240 {
04241    struct sla_trunk_ref *trunk_ref;
04242 
04243    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
04244       return NULL;
04245 
04246    trunk_ref->trunk = trunk;
04247 
04248    return trunk_ref;
04249 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 4406 of file app_meetme.c.

References ast_context_remove_extension(), AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_MAX_APP, AST_MAX_EXTENSION, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_string_field_free_all, ast_strlen_zero(), exten, free, PRIORITY_HINT, and sla_registrar.

Referenced by sla_build_station(), and sla_destroy().

04407 {
04408    struct sla_trunk_ref *trunk_ref;
04409 
04410    if (!ast_strlen_zero(station->autocontext)) {
04411       AST_RWLIST_RDLOCK(&sla_trunks);
04412       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04413          char exten[AST_MAX_EXTENSION];
04414          char hint[AST_MAX_APP];
04415          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04416          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04417          ast_context_remove_extension(station->autocontext, exten, 
04418             1, sla_registrar);
04419          ast_context_remove_extension(station->autocontext, hint, 
04420             PRIORITY_HINT, sla_registrar);
04421       }
04422       AST_RWLIST_UNLOCK(&sla_trunks);
04423    }
04424 
04425    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
04426       free(trunk_ref);
04427 
04428    ast_string_field_free_all(station);
04429    free(station);
04430 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 4392 of file app_meetme.c.

References ast_context_remove_extension(), AST_LIST_REMOVE_HEAD, ast_string_field_free_all, ast_strlen_zero(), free, and sla_registrar.

Referenced by sla_build_trunk(), and sla_destroy().

04393 {
04394    struct sla_station_ref *station_ref;
04395 
04396    if (!ast_strlen_zero(trunk->autocontext))
04397       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
04398 
04399    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
04400       free(station_ref);
04401 
04402    ast_string_field_free_all(trunk);
04403    free(trunk);
04404 }

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

Definition at line 3981 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_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), build_conf(), cid_name, 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, dispose_conf(), ast_flags::flags, free, MAX_CONFNUM, sla, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, strsep(), and dial_trunk_args::trunk_ref.

Referenced by sla_station_exec().

03982 {
03983    struct dial_trunk_args *args = data;
03984    struct ast_dial *dial;
03985    char *tech, *tech_data;
03986    enum ast_dial_result dial_res;
03987    char conf_name[MAX_CONFNUM];
03988    struct ast_conference *conf;
03989    struct ast_flags conf_flags = { 0 };
03990    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
03991    const char *cid_name = NULL, *cid_num = NULL;
03992 
03993    if (!(dial = ast_dial_create())) {
03994       ast_mutex_lock(args->cond_lock);
03995       ast_cond_signal(args->cond);
03996       ast_mutex_unlock(args->cond_lock);
03997       return NULL;
03998    }
03999 
04000    tech_data = ast_strdupa(trunk_ref->trunk->device);
04001    tech = strsep(&tech_data, "/");
04002    if (ast_dial_append(dial, tech, tech_data) == -1) {
04003       ast_mutex_lock(args->cond_lock);
04004       ast_cond_signal(args->cond);
04005       ast_mutex_unlock(args->cond_lock);
04006       ast_dial_destroy(dial);
04007       return NULL;
04008    }
04009 
04010    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
04011       cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
04012       free(trunk_ref->chan->cid.cid_name);
04013       trunk_ref->chan->cid.cid_name = NULL;
04014    }
04015    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
04016       cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
04017       free(trunk_ref->chan->cid.cid_num);
04018       trunk_ref->chan->cid.cid_num = NULL;
04019    }
04020 
04021    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
04022 
04023    if (cid_name)
04024       trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
04025    if (cid_num)
04026       trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
04027 
04028    if (dial_res != AST_DIAL_RESULT_TRYING) {
04029       ast_mutex_lock(args->cond_lock);
04030       ast_cond_signal(args->cond);
04031       ast_mutex_unlock(args->cond_lock);
04032       ast_dial_destroy(dial);
04033       return NULL;
04034    }
04035 
04036    for (;;) {
04037       unsigned int done = 0;
04038       switch ((dial_res = ast_dial_state(dial))) {
04039       case AST_DIAL_RESULT_ANSWERED:
04040          trunk_ref->trunk->chan = ast_dial_answered(dial);
04041       case AST_DIAL_RESULT_HANGUP:
04042       case AST_DIAL_RESULT_INVALID:
04043       case AST_DIAL_RESULT_FAILED:
04044       case AST_DIAL_RESULT_TIMEOUT:
04045       case AST_DIAL_RESULT_UNANSWERED:
04046          done = 1;
04047       case AST_DIAL_RESULT_TRYING:
04048       case AST_DIAL_RESULT_RINGING:
04049       case AST_DIAL_RESULT_PROGRESS:
04050       case AST_DIAL_RESULT_PROCEEDING:
04051          break;
04052       }
04053       if (done)
04054          break;
04055    }
04056 
04057    if (!trunk_ref->trunk->chan) {
04058       ast_mutex_lock(args->cond_lock);
04059       ast_cond_signal(args->cond);
04060       ast_mutex_unlock(args->cond_lock);
04061       ast_dial_join(dial);
04062       ast_dial_destroy(dial);
04063       return NULL;
04064    }
04065 
04066    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04067    ast_set_flag(&conf_flags, 
04068       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
04069       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
04070    conf = build_conf(conf_name, "", "", 1, 1, 1);
04071 
04072    ast_mutex_lock(args->cond_lock);
04073    ast_cond_signal(args->cond);
04074    ast_mutex_unlock(args->cond_lock);
04075 
04076    if (conf) {
04077       conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
04078       dispose_conf(conf);
04079       conf = NULL;
04080    }
04081 
04082    /* If the trunk is going away, it is definitely now IDLE. */
04083    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04084 
04085    trunk_ref->trunk->chan = NULL;
04086    trunk_ref->trunk->on_hold = 0;
04087 
04088    ast_dial_join(dial);
04089    ast_dial_destroy(dial);
04090 
04091    return NULL;
04092 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Definition at line 1344 of file app_meetme.c.

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

01345 {
01346    int res = 0;
01347    int confno_int = 0;
01348 
01349    AST_LIST_LOCK(&confs);
01350    if (ast_atomic_dec_and_test(&conf->refcount)) {
01351       /* Take the conference room number out of an inuse state */
01352       if ((sscanf(conf->confno, "%d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01353          conf_map[confno_int] = 0;
01354       conf_free(conf);
01355       res = 1;
01356    }
01357    AST_LIST_UNLOCK(&confs);
01358 
01359    return res;
01360 }

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

References AST_APP_ARG, ast_app_getdata(), ast_clear_flag, ast_config_destroy(), ast_config_load(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_test_flag, ast_variable_browse(), build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFIG_FILE_NAME, ast_conference::confno, LOG_DEBUG, LOG_WARNING, ast_variable::name, ast_variable::next, parse(), ast_conference::pin, ast_conference::pinadmin, ast_conference::refcount, S_OR, ast_variable::value, and var.

Referenced by conf_exec(), and count_exec().

02352 {
02353    struct ast_config *cfg;
02354    struct ast_variable *var;
02355    struct ast_conference *cnf;
02356    char *parse;
02357    AST_DECLARE_APP_ARGS(args,
02358       AST_APP_ARG(confno);
02359       AST_APP_ARG(pin);
02360       AST_APP_ARG(pinadmin);
02361    );
02362 
02363    /* Check first in the conference list */
02364    AST_LIST_LOCK(&confs);
02365    AST_LIST_TRAVERSE(&confs, cnf, list) {
02366       if (!strcmp(confno, cnf->confno)) 
02367          break;
02368    }
02369    if (cnf){
02370       cnf->refcount += refcount;
02371    }
02372    AST_LIST_UNLOCK(&confs);
02373 
02374    if (!cnf) {
02375       if (dynamic) {
02376          /* No need to parse meetme.conf */
02377          ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
02378          if (dynamic_pin) {
02379             if (dynamic_pin[0] == 'q') {
02380                /* Query the user to enter a PIN */
02381                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
02382                   return NULL;
02383             }
02384             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount);
02385          } else {
02386             cnf = build_conf(confno, "", "", make, dynamic, refcount);
02387          }
02388       } else {
02389          /* Check the config */
02390          cfg = ast_config_load(CONFIG_FILE_NAME);
02391          if (!cfg) {
02392             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
02393             return NULL;
02394          }
02395          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
02396             if (strcasecmp(var->name, "conf"))
02397                continue;
02398             
02399             if (!(parse = ast_strdupa(var->value)))
02400                return NULL;
02401             
02402             AST_NONSTANDARD_APP_ARGS(args, parse, ',');
02403             if (!strcasecmp(args.confno, confno)) {
02404                /* Bingo it's a valid conference */
02405                cnf = build_conf(args.confno,
02406                      S_OR(args.pin, ""),
02407                      S_OR(args.pinadmin, ""),
02408                      make, dynamic, refcount);
02409                break;
02410             }
02411          }
02412          if (!var) {
02413             ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
02414          }
02415          ast_config_destroy(cfg);
02416       }
02417    } else if (dynamic_pin) {
02418       /* Correct for the user selecting 'D' instead of 'd' to have
02419          someone join into a conference that has already been created
02420          with a pin. */
02421       if (dynamic_pin[0] == 'q')
02422          dynamic_pin[0] = '\0';
02423    }
02424 
02425    if (cnf) {
02426       if (confflags && !cnf->chan &&
02427           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
02428           ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
02429          ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
02430          ast_clear_flag(confflags, CONFFLAG_INTROUSER);
02431       }
02432       
02433       if (confflags && !cnf->chan &&
02434           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
02435          ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
02436          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
02437       }
02438    }
02439 
02440    return cnf;
02441 }

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 
) [static, read]

Definition at line 2293 of file app_meetme.c.

References ast_clear_flag, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_log(), ast_strdupa, ast_test_flag, ast_variables_destroy(), build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, ast_conference::confno, LOG_WARNING, ast_variable::name, ast_variable::next, ast_conference::pin, ast_conference::pinadmin, ast_conference::refcount, ast_variable::value, and var.

Referenced by conf_exec().

02295 {
02296    struct ast_variable *var;
02297    struct ast_conference *cnf;
02298 
02299    /* Check first in the conference list */
02300    AST_LIST_LOCK(&confs);
02301    AST_LIST_TRAVERSE(&confs, cnf, list) {
02302       if (!strcmp(confno, cnf->confno)) 
02303          break;
02304    }
02305    if (cnf) {
02306       cnf->refcount += refcount;
02307    }
02308    AST_LIST_UNLOCK(&confs);
02309 
02310    if (!cnf) {
02311       char *pin = NULL, *pinadmin = NULL; /* For temp use */
02312       
02313       var = ast_load_realtime("meetme", "confno", confno, NULL);
02314 
02315       if (!var)
02316          return NULL;
02317 
02318       while (var) {
02319          if (!strcasecmp(var->name, "pin")) {
02320             pin = ast_strdupa(var->value);
02321          } else if (!strcasecmp(var->name, "adminpin")) {
02322             pinadmin = ast_strdupa(var->value);
02323          }
02324          var = var->next;
02325       }
02326       ast_variables_destroy(var);
02327       
02328       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount);
02329    }
02330 
02331    if (cnf) {
02332       if (confflags && !cnf->chan &&
02333           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
02334           ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
02335          ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
02336          ast_clear_flag(confflags, CONFFLAG_INTROUSER);
02337       }
02338       
02339       if (confflags && !cnf->chan &&
02340           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
02341          ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
02342          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
02343       }
02344    }
02345 
02346    return cnf;
02347 }

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

Definition at line 2741 of file app_meetme.c.

References AST_LIST_TRAVERSE, and ast_conf_user::user_no.

02742 {
02743    struct ast_conf_user *user = NULL;
02744    int cid;
02745    
02746    sscanf(callerident, "%i", &cid);
02747    if (conf && callerident) {
02748       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
02749          if (cid == user->user_no)
02750             return user;
02751       }
02752    }
02753    return NULL;
02754 }

static char* istalking ( int  x  )  [static]

Definition at line 564 of file app_meetme.c.

Referenced by meetme_cmd().

00565 {
00566    if (x > 0)
00567       return "(talking)";
00568    else if (x < 0)
00569       return "(unmonitored)";
00570    else 
00571       return "(not talking)";
00572 }

static int load_config ( int  reload  )  [static]

Definition at line 4757 of file app_meetme.c.

References load_config_meetme(), and sla_load_config().

04758 {
04759    int res = 0;
04760 
04761    load_config_meetme();
04762    if (!reload)
04763       res = sla_load_config();
04764 
04765    return res;
04766 }

static void load_config_meetme ( void   )  [static]

Definition at line 3069 of file app_meetme.c.

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

Referenced by load_config().

03070 {
03071    struct ast_config *cfg;
03072    const char *val;
03073 
03074    audio_buffers = DEFAULT_AUDIO_BUFFERS;
03075 
03076    if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
03077       return;
03078 
03079    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03080       if ((sscanf(val, "%d", &audio_buffers) != 1)) {
03081          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03082          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03083       } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) {
03084          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03085             ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS);
03086          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03087       }
03088       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03089          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03090    }
03091 
03092    ast_config_destroy(cfg);
03093 }

static int load_module ( void   )  [static]

Definition at line 4791 of file app_meetme.c.

References action_meetmemute(), action_meetmeunmute(), admin_exec(), ARRAY_LEN, ast_cli_register_multiple(), ast_devstate_prov_add(), ast_manager_register, ast_register_application(), conf_exec(), count_exec(), EVENT_FLAG_CALL, load_config(), meetmestate(), sla_state(), sla_station_exec(), and sla_trunk_exec().

04792 {
04793    int res = 0;
04794 
04795    res |= load_config(0);
04796 
04797    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
04798    res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 
04799                 action_meetmemute, "Mute a Meetme user");
04800    res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 
04801                 action_meetmeunmute, "Unmute a Meetme user");
04802    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
04803    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
04804    res |= ast_register_application(app, conf_exec, synopsis, descrip);
04805    res |= ast_register_application(slastation_app, sla_station_exec,
04806                slastation_synopsis, slastation_desc);
04807    res |= ast_register_application(slatrunk_app, sla_trunk_exec,
04808                slatrunk_synopsis, slatrunk_desc);
04809 
04810    res |= ast_devstate_prov_add("Meetme", meetmestate);
04811    res |= ast_devstate_prov_add("SLA", sla_state);
04812 
04813    return res;
04814 }

static int meetme_cmd ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 820 of file app_meetme.c.

References admin_exec(), ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_conference::isdynamic, istalking(), ast_conf_user::jointime, LOG_DEBUG, ast_conference::markedusers, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_OR, ast_conference::start, ast_conf_user::talking, total, ast_conf_user::user_no, ast_conf_user::userflags, and ast_conference::users.

00821 {
00822    /* Process the command */
00823    struct ast_conference *cnf;
00824    struct ast_conf_user *user;
00825    int hr, min, sec;
00826    int i = 0, total = 0;
00827    time_t now;
00828    char *header_format = "%-14s %-14s %-10s %-8s  %-8s\n";
00829    char *data_format = "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s\n";
00830    char cmdline[1024] = "";
00831 
00832    if (argc > 8)
00833       ast_cli(fd, "Invalid Arguments.\n");
00834    /* Check for length so no buffer will overflow... */
00835    for (i = 0; i < argc; i++) {
00836       if (strlen(argv[i]) > 100)
00837          ast_cli(fd, "Invalid Arguments.\n");
00838    }
00839    if (argc == 1) {
00840       /* 'MeetMe': List all the conferences */  
00841       now = time(NULL);
00842       AST_LIST_LOCK(&confs);
00843       if (AST_LIST_EMPTY(&confs)) {
00844          ast_cli(fd, "No active MeetMe conferences.\n");
00845          AST_LIST_UNLOCK(&confs);
00846          return RESULT_SUCCESS;
00847       }
00848       ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
00849       AST_LIST_TRAVERSE(&confs, cnf, list) {
00850          if (cnf->markedusers == 0)
00851             strcpy(cmdline, "N/A ");
00852          else 
00853             snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers);
00854          hr = (now - cnf->start) / 3600;
00855          min = ((now - cnf->start) % 3600) / 60;
00856          sec = (now - cnf->start) % 60;
00857 
00858          ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static");
00859 
00860          total += cnf->users;    
00861       }
00862       AST_LIST_UNLOCK(&confs);
00863       ast_cli(fd, "* Total number of MeetMe users: %d\n", total);
00864       return RESULT_SUCCESS;
00865    }
00866    if (argc < 3)
00867       return RESULT_SHOWUSAGE;
00868    ast_copy_string(cmdline, argv[2], sizeof(cmdline));   /* Argv 2: conference number */
00869    if (strstr(argv[1], "lock")) {   
00870       if (strcmp(argv[1], "lock") == 0) {
00871          /* Lock */
00872          strncat(cmdline, "|L", sizeof(cmdline) - strlen(cmdline) - 1);
00873       } else {
00874          /* Unlock */
00875          strncat(cmdline, "|l", sizeof(cmdline) - strlen(cmdline) - 1);
00876       }
00877    } else if (strstr(argv[1], "mute")) { 
00878       if (argc < 4)
00879          return RESULT_SHOWUSAGE;
00880       if (strcmp(argv[1], "mute") == 0) {
00881          /* Mute */
00882          if (strcmp(argv[3], "all") == 0) {
00883             strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1);
00884          } else {
00885             strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1);   
00886             strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00887          }
00888       } else {
00889          /* Unmute */
00890          if (strcmp(argv[3], "all") == 0) {
00891             strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1);
00892          } else {
00893             strncat(cmdline, "|m|", sizeof(cmdline) - strlen(cmdline) - 1);
00894             strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00895          }
00896       }
00897    } else if (strcmp(argv[1], "kick") == 0) {
00898       if (argc < 4)
00899          return RESULT_SHOWUSAGE;
00900       if (strcmp(argv[3], "all") == 0) {
00901          /* Kick all */
00902          strncat(cmdline, "|K", sizeof(cmdline) - strlen(cmdline) - 1);
00903       } else {
00904          /* Kick a single user */
00905          strncat(cmdline, "|k|", sizeof(cmdline) - strlen(cmdline) - 1);
00906          strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00907       }  
00908    } else if(strcmp(argv[1], "list") == 0) {
00909       int concise = ( 4 == argc && ( !strcasecmp(argv[3], "concise") ) );
00910       /* List all the users in a conference */
00911       if (AST_LIST_EMPTY(&confs)) {
00912          if ( !concise )
00913             ast_cli(fd, "No active conferences.\n");
00914          return RESULT_SUCCESS;  
00915       }
00916       /* Find the right conference */
00917       AST_LIST_LOCK(&confs);
00918       AST_LIST_TRAVERSE(&confs, cnf, list) {
00919          if (strcmp(cnf->confno, argv[2]) == 0)
00920             break;
00921       }
00922       if (!cnf) {
00923          if ( !concise )
00924             ast_cli(fd, "No such conference: %s.\n",argv[2]);
00925          AST_LIST_UNLOCK(&confs);
00926          return RESULT_SUCCESS;
00927       }
00928       /* Show all the users */
00929       time(&now);
00930       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
00931          hr = (now - user->jointime) / 3600;
00932          min = ((now - user->jointime) % 3600) / 60;
00933          sec = (now - user->jointime) % 60;
00934          if ( !concise )
00935             ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %02d:%02d:%02d\n",
00936                user->user_no,
00937                S_OR(user->chan->cid.cid_num, "<unknown>"),
00938                S_OR(user->chan->cid.cid_name, "<no name>"),
00939                user->chan->name,
00940                user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
00941                user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
00942                user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
00943                istalking(user->talking), hr, min, sec); 
00944          else 
00945             ast_cli(fd, "%d!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
00946                user->user_no,
00947                S_OR(user->chan->cid.cid_num, ""),
00948                S_OR(user->chan->cid.cid_name, ""),
00949                user->chan->name,
00950                user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
00951                user->userflags  & CONFFLAG_MONITOR ? "1" : "",
00952                user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)  ? "1" : "",
00953                user->talking, hr, min, sec);
00954          
00955       }
00956       if ( !concise )
00957          ast_cli(fd,"%d users in that conference.\n",cnf->users);
00958       AST_LIST_UNLOCK(&confs);
00959       return RESULT_SUCCESS;
00960    } else 
00961       return RESULT_SHOWUSAGE;
00962    ast_log(LOG_DEBUG, "Cmdline: %s\n", cmdline);
00963    admin_exec(NULL, cmdline);
00964 
00965    return 0;
00966 }

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

Definition at line 2911 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, 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, LOG_NOTICE, and ast_conf_user::user_no.

Referenced by action_meetmemute(), and action_meetmeunmute().

02912 {
02913    struct ast_conference *conf;
02914    struct ast_conf_user *user;
02915    const char *confid = astman_get_header(m, "Meetme");
02916    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
02917    int userno;
02918 
02919    if (ast_strlen_zero(confid)) {
02920       astman_send_error(s, m, "Meetme conference not specified");
02921       return 0;
02922    }
02923 
02924    if (ast_strlen_zero(userid)) {
02925       astman_send_error(s, m, "Meetme user number not specified");
02926       return 0;
02927    }
02928 
02929    userno = strtoul(userid, &userid, 10);
02930 
02931    if (*userid) {
02932       astman_send_error(s, m, "Invalid user number");
02933       return 0;
02934    }
02935 
02936    /* Look in the conference list */
02937    AST_LIST_LOCK(&confs);
02938    AST_LIST_TRAVERSE(&confs, conf, list) {
02939       if (!strcmp(confid, conf->confno))
02940          break;
02941    }
02942 
02943    if (!conf) {
02944       AST_LIST_UNLOCK(&confs);
02945       astman_send_error(s, m, "Meetme conference does not exist");
02946       return 0;
02947    }
02948 
02949    AST_LIST_TRAVERSE(&conf->userlist, user, list)
02950       if (user->user_no == userno)
02951          break;
02952 
02953    if (!user) {
02954       AST_LIST_UNLOCK(&confs);
02955       astman_send_error(s, m, "User number not found");
02956       return 0;
02957    }
02958 
02959    if (mute)
02960       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
02961    else
02962       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);  /* request user unmuting */
02963 
02964    AST_LIST_UNLOCK(&confs);
02965 
02966    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);
02967 
02968    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
02969    return 0;
02970 }

static int meetmestate ( const char *  data  )  [static]

Callback for devicestate providers.

Definition at line 3047 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, and ast_conference::users.

Referenced by load_module().

03048 {
03049    struct ast_conference *conf;
03050 
03051    /* Find conference */
03052    AST_LIST_LOCK(&confs);
03053    AST_LIST_TRAVERSE(&confs, conf, list) {
03054       if (!strcmp(data, conf->confno))
03055          break;
03056    }
03057    AST_LIST_UNLOCK(&confs);
03058    if (!conf)
03059       return AST_DEVICE_INVALID;
03060 
03061 
03062    /* SKREP to fill */
03063    if (!conf->users)
03064       return AST_DEVICE_NOT_INUSE;
03065 
03066    return AST_DEVICE_INUSE;
03067 }

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

Definition at line 4251 of file app_meetme.c.

References ALL_TRUNK_REFS, ast_calloc, AST_LIST_INSERT_HEAD, ast_mutex_lock(), ast_mutex_unlock(), 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().

04252 {
04253    struct sla_ringing_trunk *ringing_trunk;
04254 
04255    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
04256       return NULL;
04257    
04258    ringing_trunk->trunk = trunk;
04259    ringing_trunk->ring_begin = ast_tvnow();
04260 
04261    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
04262 
04263    ast_mutex_lock(&sla.lock);
04264    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
04265    ast_mutex_unlock(&sla.lock);
04266 
04267    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04268 
04269    return ringing_trunk;
04270 }

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

Definition at line 2982 of file app_meetme.c.

References ast_closestream(), 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::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.

02983 {
02984    struct ast_conference *cnf = args;
02985    struct ast_frame *f=NULL;
02986    int flags;
02987    struct ast_filestream *s=NULL;
02988    int res=0;
02989    int x;
02990    const char *oldrecordingfilename = NULL;
02991 
02992    if (!cnf || !cnf->lchan) {
02993       pthread_exit(0);
02994    }
02995 
02996    ast_stopstream(cnf->lchan);
02997    flags = O_CREAT|O_TRUNC|O_WRONLY;
02998 
02999 
03000    cnf->recording = MEETME_RECORD_ACTIVE;
03001    while (ast_waitfor(cnf->lchan, -1) > -1) {
03002       if (cnf->recording == MEETME_RECORD_TERMINATE) {
03003          AST_LIST_LOCK(&confs);
03004          AST_LIST_UNLOCK(&confs);
03005          break;
03006       }
03007       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
03008          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
03009          oldrecordingfilename = cnf->recordingfilename;
03010       }
03011       
03012       f = ast_read(cnf->lchan);
03013       if (!f) {
03014          res = -1;
03015          break;
03016       }
03017       if (f->frametype == AST_FRAME_VOICE) {
03018          ast_mutex_lock(&cnf->listenlock);
03019          for (x=0;x<AST_FRAME_BITS;x++) {
03020             /* Free any translations that have occured */
03021             if (cnf->transframe[x]) {
03022                ast_frfree(cnf->transframe[x]);
03023                cnf->transframe[x] = NULL;
03024             }
03025          }
03026          if (cnf->origframe)
03027             ast_frfree(cnf->origframe);
03028          cnf->origframe = ast_frdup(f);
03029          ast_mutex_unlock(&cnf->listenlock);
03030          if (s)
03031             res = ast_writestream(s, f);
03032          if (res) {
03033             ast_frfree(f);
03034             break;
03035          }
03036       }
03037       ast_frfree(f);
03038    }
03039    cnf->recording = MEETME_RECORD_OFF;
03040    if (s)
03041       ast_closestream(s);
03042    
03043    pthread_exit(0);
03044 }

static int reload ( void   )  [static]

Definition at line 4816 of file app_meetme.c.

References load_config().

04817 {
04818    return load_config(1);
04819 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

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

00685 {
00686    signed char zero_volume = 0;
00687 
00688    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00689    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00690 }

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

Definition at line 3228 of file app_meetme.c.

References admin_exec(), ALL_TRUNK_REFS, ast_answer(), ast_cond_signal(), ast_dial_destroy(), ast_dial_join(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, build_conf(), run_station_args::cond, run_station_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dispose_conf(), ast_flags::flags, MAX_CONFNUM, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, run_station_args::station, and run_station_args::trunk_ref.

Referenced by sla_handle_dial_state_event().

03229 {
03230    struct sla_station *station;
03231    struct sla_trunk_ref *trunk_ref;
03232    char conf_name[MAX_CONFNUM];
03233    struct ast_flags conf_flags = { 0 };
03234    struct ast_conference *conf;
03235 
03236    {
03237       struct run_station_args *args = data;
03238       station = args->station;
03239       trunk_ref = args->trunk_ref;
03240       ast_mutex_lock(args->cond_lock);
03241       ast_cond_signal(args->cond);
03242       ast_mutex_unlock(args->cond_lock);
03243       /* args is no longer valid here. */
03244    }
03245 
03246    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
03247    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
03248    ast_set_flag(&conf_flags, 
03249       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
03250    ast_answer(trunk_ref->chan);
03251    conf = build_conf(conf_name, "", "", 0, 0, 1);
03252    if (conf) {
03253       conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
03254       dispose_conf(conf);
03255       conf = NULL;
03256    }
03257    trunk_ref->chan = NULL;
03258    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
03259       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
03260       strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
03261       admin_exec(NULL, conf_name);
03262       trunk_ref->trunk->hold_stations = 0;
03263       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03264    }
03265 
03266    ast_dial_join(station->dial);
03267    ast_dial_destroy(station->dial);
03268    station->dial = NULL;
03269 
03270    return NULL;
03271 }

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

Definition at line 613 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

00614 {
00615    char gain_adjust;
00616 
00617    /* attempt to make the adjustment in the channel driver;
00618       if successful, don't adjust in the frame reading routine
00619    */
00620    gain_adjust = gain_map[volume + 5];
00621 
00622    return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00623 }

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

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

00602 {
00603    char gain_adjust;
00604 
00605    /* attempt to make the adjustment in the channel driver;
00606       if successful, don't adjust in the frame reading routine
00607    */
00608    gain_adjust = gain_map[volume + 5];
00609 
00610    return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00611 }

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

Definition at line 4550 of file app_meetme.c.

References AST_LIST_INSERT_TAIL, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdupa, create_trunk_ref(), free, LOG_ERROR, LOG_WARNING, name, sla_create_station_ref(), SLA_TRUNK_STATE_IDLE, strsep(), and ast_variable::value.

Referenced by sla_build_station().

04551 {
04552    struct sla_trunk *trunk;
04553    struct sla_trunk_ref *trunk_ref;
04554    struct sla_station_ref *station_ref;
04555    char *trunk_name, *options, *cur;
04556 
04557    options = ast_strdupa(var->value);
04558    trunk_name = strsep(&options, ",");
04559    
04560    AST_RWLIST_RDLOCK(&sla_trunks);
04561    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04562       if (!strcasecmp(trunk->name, trunk_name))
04563          break;
04564    }
04565 
04566    AST_RWLIST_UNLOCK(&sla_trunks);
04567    if (!trunk) {
04568       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
04569       return;
04570    }
04571    if (!(trunk_ref = create_trunk_ref(trunk)))
04572       return;
04573    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
04574 
04575    while ((cur = strsep(&options, ","))) {
04576       char *name, *value = cur;
04577       name = strsep(&value, "=");
04578       if (!strcasecmp(name, "ringtimeout")) {
04579          if (sscanf(value, "%u", &trunk_ref->ring_timeout) != 1) {
04580             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
04581                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04582             trunk_ref->ring_timeout = 0;
04583          }
04584       } else if (!strcasecmp(name, "ringdelay")) {
04585          if (sscanf(value, "%u", &trunk_ref->ring_delay) != 1) {
04586             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
04587                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04588             trunk_ref->ring_delay = 0;
04589          }
04590       } else {
04591          ast_log(LOG_WARNING, "Invalid option '%s' for "
04592             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
04593       }
04594    }
04595 
04596    if (!(station_ref = sla_create_station_ref(station))) {
04597       free(trunk_ref);
04598       return;
04599    }
04600    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
04601    AST_RWLIST_WRLOCK(&sla_trunks);
04602    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
04603    AST_RWLIST_UNLOCK(&sla_trunks);
04604    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
04605 }

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

Definition at line 4607 of file app_meetme.c.

References ast_add_extension2(), ast_calloc, ast_context_find_or_create(), ast_free, 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(), context, destroy_station(), exten, free, ast_variable::lineno, LOG_ERROR, LOG_WARNING, ast_variable::name, name, ast_variable::next, PRIORITY_HINT, sla_add_trunk_to_station(), SLA_CONFIG_FILE, SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, ast_variable::value, and var.

Referenced by sla_load_config().

04608 {
04609    struct sla_station *station;
04610    struct ast_variable *var;
04611    const char *dev;
04612 
04613    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
04614       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
04615       return -1;
04616    }
04617 
04618    if (!(station = ast_calloc(1, sizeof(*station))))
04619       return -1;
04620    if (ast_string_field_init(station, 32)) {
04621       free(station);
04622       return -1;
04623    }
04624 
04625    ast_string_field_set(station, name, cat);
04626    ast_string_field_set(station, device, dev);
04627 
04628    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04629       if (!strcasecmp(var->name, "trunk"))
04630          sla_add_trunk_to_station(station, var);
04631       else if (!strcasecmp(var->name, "autocontext"))
04632          ast_string_field_set(station, autocontext, var->value);
04633       else if (!strcasecmp(var->name, "ringtimeout")) {
04634          if (sscanf(var->value, "%u", &station->ring_timeout) != 1) {
04635             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
04636                var->value, station->name);
04637             station->ring_timeout = 0;
04638          }
04639       } else if (!strcasecmp(var->name, "ringdelay")) {
04640          if (sscanf(var->value, "%u", &station->ring_delay) != 1) {
04641             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
04642                var->value, station->name);
04643             station->ring_delay = 0;
04644          }
04645       } else if (!strcasecmp(var->name, "hold")) {
04646          if (!strcasecmp(var->value, "private"))
04647             station->hold_access = SLA_HOLD_PRIVATE;
04648          else if (!strcasecmp(var->value, "open"))
04649             station->hold_access = SLA_HOLD_OPEN;
04650          else {
04651             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
04652                var->value, station->name);
04653          }
04654 
04655       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
04656          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
04657             var->name, var->lineno, SLA_CONFIG_FILE);
04658       }
04659    }
04660 
04661    if (!ast_strlen_zero(station->autocontext)) {
04662       struct ast_context *context;
04663       struct sla_trunk_ref *trunk_ref;
04664       context = ast_context_find_or_create(NULL, station->autocontext, sla_registrar);
04665       if (!context) {
04666          ast_log(LOG_ERROR, "Failed to automatically find or create "
04667             "context '%s' for SLA!\n", station->autocontext);
04668          destroy_station(station);
04669          return -1;
04670       }
04671       /* The extension for when the handset goes off-hook.
04672        * exten => station1,1,SLAStation(station1) */
04673       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
04674          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free, sla_registrar)) {
04675          ast_log(LOG_ERROR, "Failed to automatically create extension "
04676             "for trunk '%s'!\n", station->name);
04677          destroy_station(station);
04678          return -1;
04679       }
04680       AST_RWLIST_RDLOCK(&sla_trunks);
04681       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04682          char exten[AST_MAX_EXTENSION];
04683          char hint[AST_MAX_APP];
04684          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04685          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04686          /* Extension for this line button 
04687           * exten => station1_line1,1,SLAStation(station1_line1) */
04688          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
04689             NULL, NULL, slastation_app, ast_strdup(exten), ast_free, sla_registrar)) {
04690             ast_log(LOG_ERROR, "Failed to automatically create extension "
04691                "for trunk '%s'!\n", station->name);
04692             destroy_station(station);
04693             return -1;
04694          }
04695          /* Hint for this line button 
04696           * exten => station1_line1,hint,SLA:station1_line1 */
04697          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
04698             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
04699             ast_log(LOG_ERROR, "Failed to automatically create hint "
04700                "for trunk '%s'!\n", station->name);
04701             destroy_station(station);
04702             return -1;
04703          }
04704       }
04705       AST_RWLIST_UNLOCK(&sla_trunks);
04706    }
04707 
04708    AST_RWLIST_WRLOCK(&sla_stations);
04709    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
04710    AST_RWLIST_UNLOCK(&sla_stations);
04711 
04712    return 0;
04713 }

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

Definition at line 4472 of file app_meetme.c.

References ast_add_extension2(), ast_calloc, ast_context_find_or_create(), ast_false(), ast_free, 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(), context, destroy_trunk(), free, ast_variable::lineno, LOG_ERROR, LOG_WARNING, ast_variable::name, name, ast_variable::next, sla_check_device(), SLA_CONFIG_FILE, SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, ast_variable::value, and var.

Referenced by sla_load_config().

04473 {
04474    struct sla_trunk *trunk;
04475    struct ast_variable *var;
04476    const char *dev;
04477 
04478    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
04479       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
04480       return -1;
04481    }
04482 
04483    if (sla_check_device(dev)) {
04484       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
04485          cat, dev);
04486       return -1;
04487    }
04488 
04489    if (!(trunk = ast_calloc(1, sizeof(*trunk))))
04490       return -1;
04491    if (ast_string_field_init(trunk, 32)) {
04492       free(trunk);
04493       return -1;
04494    }
04495 
04496    ast_string_field_set(trunk, name, cat);
04497    ast_string_field_set(trunk, device, dev);
04498 
04499    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04500       if (!strcasecmp(var->name, "autocontext"))
04501          ast_string_field_set(trunk, autocontext, var->value);
04502       else if (!strcasecmp(var->name, "ringtimeout")) {
04503          if (sscanf(var->value, "%u", &trunk->ring_timeout) != 1) {
04504             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
04505                var->value, trunk->name);
04506             trunk->ring_timeout = 0;
04507          }
04508       } else if (!strcasecmp(var->name, "barge"))
04509          trunk->barge_disabled = ast_false(var->value);
04510       else if (!strcasecmp(var->name, "hold")) {
04511          if (!strcasecmp(var->value, "private"))
04512             trunk->hold_access = SLA_HOLD_PRIVATE;
04513          else if (!strcasecmp(var->value, "open"))
04514             trunk->hold_access = SLA_HOLD_OPEN;
04515          else {
04516             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
04517                var->value, trunk->name);
04518          }
04519       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
04520          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
04521             var->name, var->lineno, SLA_CONFIG_FILE);
04522       }
04523    }
04524 
04525    if (!ast_strlen_zero(trunk->autocontext)) {
04526       struct ast_context *context;
04527       context = ast_context_find_or_create(NULL, trunk->autocontext, sla_registrar);
04528       if (!context) {
04529          ast_log(LOG_ERROR, "Failed to automatically find or create "
04530             "context '%s' for SLA!\n", trunk->autocontext);
04531          destroy_trunk(trunk);
04532          return -1;
04533       }
04534       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
04535          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free, sla_registrar)) {
04536          ast_log(LOG_ERROR, "Failed to automatically create extension "
04537             "for trunk '%s'!\n", trunk->name);
04538          destroy_trunk(trunk);
04539          return -1;
04540       }
04541    }
04542 
04543    AST_RWLIST_WRLOCK(&sla_trunks);
04544    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
04545    AST_RWLIST_UNLOCK(&sla_trunks);
04546 
04547    return 0;
04548 }

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

03846 {
03847    struct sla_station *station;
03848    int res = 0;
03849 
03850    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
03851       struct sla_ringing_trunk *ringing_trunk;
03852       int time_left;
03853 
03854       /* Ignore stations already ringing */
03855       if (sla_check_ringing_station(station))
03856          continue;
03857 
03858       /* Ignore stations already on a call */
03859       if (sla_check_inuse_station(station))
03860          continue;
03861 
03862       /* Ignore stations that don't have one of their trunks ringing */
03863       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
03864          continue;
03865 
03866       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
03867          continue;
03868 
03869       /* If there is no time left, then the station needs to start ringing.
03870        * Return non-zero so that an event will be queued up an event to 
03871        * make that happen. */
03872       if (time_left <= 0) {
03873          res = 1;
03874          continue;
03875       }
03876 
03877       if (time_left < *timeout)
03878          *timeout = time_left;
03879    }
03880 
03881    return res;
03882 }

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

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, sla_ringing_station::ring_begin, sla_ringing_trunk::ring_begin, sla, SLA_STATION_HANGUP_TIMEOUT, sla_stop_ringing_station(), sla_ringing_station::station, and sla_ringing_trunk::trunk.

Referenced by sla_process_timers().

03763 {
03764    struct sla_ringing_trunk *ringing_trunk;
03765    struct sla_ringing_station *ringing_station;
03766    int res = 0;
03767 
03768    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03769       unsigned int ring_timeout = 0;
03770       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
03771       struct sla_trunk_ref *trunk_ref;
03772 
03773       /* If there are any ring timeouts specified for a specific trunk
03774        * on the station, then use the highest per-trunk ring timeout.
03775        * Otherwise, use the ring timeout set for the entire station. */
03776       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03777          struct sla_station_ref *station_ref;
03778          int trunk_time_elapsed, trunk_time_left;
03779 
03780          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03781             if (ringing_trunk->trunk == trunk_ref->trunk)
03782                break;
03783          }
03784          if (!ringing_trunk)
03785             continue;
03786 
03787          /* If there is a trunk that is ringing without a timeout, then the
03788           * only timeout that could matter is a global station ring timeout. */
03789          if (!trunk_ref->ring_timeout)
03790             break;
03791 
03792          /* This trunk on this station is ringing and has a timeout.
03793           * However, make sure this trunk isn't still ringing from a
03794           * previous timeout.  If so, don't consider it. */
03795          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
03796             if (station_ref->station == ringing_station->station)
03797                break;
03798          }
03799          if (station_ref)
03800             continue;
03801 
03802          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03803          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
03804          if (trunk_time_left > final_trunk_time_left)
03805             final_trunk_time_left = trunk_time_left;
03806       }
03807 
03808       /* No timeout was found for ringing trunks, and no timeout for the entire station */
03809       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
03810          continue;
03811 
03812       /* Compute how much time is left for a global station timeout */
03813       if (ringing_station->station->ring_timeout) {
03814          ring_timeout = ringing_station->station->ring_timeout;
03815          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
03816          time_left = (ring_timeout * 1000) - time_elapsed;
03817       }
03818 
03819       /* If the time left based on the per-trunk timeouts is smaller than the
03820        * global station ring timeout, use that. */
03821       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
03822          time_left = final_trunk_time_left;
03823 
03824       /* If there is no time left, the station needs to stop ringing */
03825       if (time_left <= 0) {
03826          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03827          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
03828          res = 1;
03829          continue;
03830       }
03831 
03832       /* There is still some time left for this station to ring, so save that
03833        * timeout if it is the first event scheduled to occur */
03834       if (time_left < *timeout)
03835          *timeout = time_left;
03836    }
03837    AST_LIST_TRAVERSE_SAFE_END
03838 
03839    return res;
03840 }

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

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, pbx_builtin_setvar_helper(), sla_ringing_trunk::ring_begin, sla, sla_stop_ringing_trunk(), and sla_ringing_trunk::trunk.

Referenced by sla_process_timers().

03733 {
03734    struct sla_ringing_trunk *ringing_trunk;
03735    int res = 0;
03736 
03737    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03738       int time_left, time_elapsed;
03739       if (!ringing_trunk->trunk->ring_timeout)
03740          continue;
03741       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03742       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
03743       if (time_left <= 0) {
03744          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
03745          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03746          sla_stop_ringing_trunk(ringing_trunk);
03747          res = 1;
03748          continue;
03749       }
03750       if (time_left < *timeout)
03751          *timeout = time_left;
03752    }
03753    AST_LIST_TRAVERSE_SAFE_END
03754 
03755    return res;
03756 }

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

References ast_device_state_changed(), and AST_LIST_TRAVERSE.

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

03205 {
03206    struct sla_station *station;
03207    struct sla_trunk_ref *trunk_ref;
03208 
03209    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
03210       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03211          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
03212             || trunk_ref == exclude)
03213             continue;
03214          trunk_ref->state = state;
03215          ast_device_state_changed("SLA:%s_%s", station->name, trunk->name);
03216          break;
03217       }
03218    }
03219 }

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

Definition at line 4459 of file app_meetme.c.

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

Referenced by sla_build_trunk().

04460 {
04461    char *tech, *tech_data;
04462 
04463    tech_data = ast_strdupa(device);
04464    tech = strsep(&tech_data, "/");
04465 
04466    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
04467       return -1;
04468 
04469    return 0;
04470 }

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

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, free, sla_failed_station::last_try, sla, and sla_failed_station::station.

Referenced by sla_ring_stations().

03481 {
03482    struct sla_failed_station *failed_station;
03483    int res = 0;
03484 
03485    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
03486       if (station != failed_station->station)
03487          continue;
03488       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
03489          AST_LIST_REMOVE_CURRENT(&sla.failed_stations, entry);
03490          free(failed_station);
03491          break;
03492       }
03493       res = 1;
03494    }
03495    AST_LIST_TRAVERSE_SAFE_END
03496 
03497    return res;
03498 }

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

Check to see if a station is in use.

Definition at line 3566 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

03567 {
03568    struct sla_trunk_ref *trunk_ref;
03569 
03570    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03571       if (trunk_ref->chan)
03572          return 1;
03573    }
03574 
03575    return 0;
03576 }

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

03466 {
03467    struct sla_ringing_station *ringing_station;
03468 
03469    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
03470       if (station == ringing_station->station)
03471          return 1;
03472    }
03473 
03474    return 0;
03475 }

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

References sla_ringing_trunk::ring_begin, sla_choose_ringing_trunk(), sla_find_trunk_ref(), and sla_ringing_trunk::trunk.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

03598 {
03599    struct sla_trunk_ref *trunk_ref;
03600    unsigned int delay = UINT_MAX;
03601    int time_left, time_elapsed;
03602 
03603    if (!ringing_trunk)
03604       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
03605    else
03606       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
03607 
03608    if (!ringing_trunk || !trunk_ref)
03609       return delay;
03610 
03611    /* If this station has a ring delay specific to the highest priority
03612     * ringing trunk, use that.  Otherwise, use the ring delay specified
03613     * globally for the station. */
03614    delay = trunk_ref->ring_delay;
03615    if (!delay)
03616       delay = station->ring_delay;
03617    if (!delay)
03618       return INT_MAX;
03619 
03620    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03621    time_left = (delay * 1000) - time_elapsed;
03622 
03623    return time_left;
03624 }

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

Definition at line 3125 of file app_meetme.c.

References AST_LIST_TRAVERSE, SLA_HOLD_PRIVATE, and SLA_TRUNK_STATE_ONHOLD_BYME.

Referenced by sla_find_trunk_ref_byname().

03127 {
03128    struct sla_station_ref *station_ref;
03129    struct sla_trunk_ref *trunk_ref;
03130 
03131    /* For each station that has this call on hold, check for private hold. */
03132    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03133       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03134          if (trunk_ref->trunk != trunk || station_ref->station == station)
03135             continue;
03136          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03137             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03138             return 1;
03139          return 0;
03140       }
03141    }
03142 
03143    return 0;
03144 }

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

References AST_LIST_TRAVERSE.

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

03333 {
03334    struct sla_station_ref *timed_out_station;
03335 
03336    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
03337       if (station == timed_out_station->station)
03338          return 1;
03339    }
03340 
03341    return 0;
03342 }

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

References AST_LIST_TRAVERSE, and SLA_TRUNK_STATE_IDLE.

Referenced by sla_station_exec().

04097 {
04098    struct sla_trunk_ref *trunk_ref = NULL;
04099 
04100    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04101       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
04102          break;
04103    }
04104 
04105    return trunk_ref;
04106 }

static struct sla_ringing_trunk* sla_choose_ringing_trunk ( struct sla_station station,
struct sla_trunk_ref **  trunk_ref,
int  remove 
) [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 3352 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(), and sla_ringing_trunk::trunk.

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

03354 {
03355    struct sla_trunk_ref *s_trunk_ref;
03356    struct sla_ringing_trunk *ringing_trunk = NULL;
03357 
03358    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
03359       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03360          /* Make sure this is the trunk we're looking for */
03361          if (s_trunk_ref->trunk != ringing_trunk->trunk)
03362             continue;
03363 
03364          /* This trunk on the station is ringing.  But, make sure this station
03365           * didn't already time out while this trunk was ringing. */
03366          if (sla_check_timed_out_station(ringing_trunk, station))
03367             continue;
03368 
03369          if (remove)
03370             AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03371 
03372          if (trunk_ref)
03373             *trunk_ref = s_trunk_ref;
03374 
03375          break;
03376       }
03377       AST_LIST_TRAVERSE_SAFE_END
03378    
03379       if (ringing_trunk)
03380          break;
03381    }
03382 
03383    return ringing_trunk;
03384 }

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

Definition at line 3190 of file app_meetme.c.

References ast_calloc, sla_ringing_station::ring_begin, and sla_ringing_station::station.

Referenced by sla_ring_station().

03191 {
03192    struct sla_ringing_station *ringing_station;
03193 
03194    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
03195       return NULL;
03196 
03197    ringing_station->station = station;
03198    ringing_station->ring_begin = ast_tvnow();
03199 
03200    return ringing_station;
03201 }

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

Definition at line 3178 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().

03179 {
03180    struct sla_station_ref *station_ref;
03181 
03182    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
03183       return NULL;
03184 
03185    station_ref->station = station;
03186 
03187    return station_ref;
03188 }

static void sla_destroy ( void   )  [static]

Definition at line 4432 of file app_meetme.c.

References ast_cond_destroy(), ast_cond_signal(), 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(), and sla.

Referenced by unload_module().

04433 {
04434    struct sla_trunk *trunk;
04435    struct sla_station *station;
04436 
04437    AST_RWLIST_WRLOCK(&sla_trunks);
04438    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
04439       destroy_trunk(trunk);
04440    AST_RWLIST_UNLOCK(&sla_trunks);
04441 
04442    AST_RWLIST_WRLOCK(&sla_stations);
04443    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
04444       destroy_station(station);
04445    AST_RWLIST_UNLOCK(&sla_stations);
04446 
04447    if (sla.thread != AST_PTHREADT_NULL) {
04448       ast_mutex_lock(&sla.lock);
04449       sla.stop = 1;
04450       ast_cond_signal(&sla.cond);
04451       ast_mutex_unlock(&sla.lock);
04452       pthread_join(sla.thread, NULL);
04453    }
04454 
04455    ast_mutex_destroy(&sla.lock);
04456    ast_cond_destroy(&sla.cond);
04457 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 3323 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

03324 {
03325    sla_queue_event(SLA_EVENT_DIAL_STATE);
03326 }

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

References AST_RWLIST_TRAVERSE.

Referenced by sla_station_exec().

03114 {
03115    struct sla_station *station = NULL;
03116 
03117    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03118       if (!strcasecmp(station->name, name))
03119          break;
03120    }
03121 
03122    return station;
03123 }

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

References AST_RWLIST_TRAVERSE.

Referenced by sla_trunk_exec().

03099 {
03100    struct sla_trunk *trunk = NULL;
03101 
03102    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03103       if (!strcasecmp(trunk->name, name))
03104          break;
03105    }
03106 
03107    return trunk;
03108 }

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

Definition at line 3578 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_check_station_delay().

03580 {
03581    struct sla_trunk_ref *trunk_ref = NULL;
03582 
03583    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03584       if (trunk_ref->trunk == trunk)
03585          break;
03586    }
03587 
03588    return trunk_ref;
03589 }

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

References AST_LIST_TRAVERSE, sla_check_station_hold_access(), SLA_HOLD_PRIVATE, SLA_TRUNK_STATE_ONHOLD_BYME, and SLA_TRUNK_STATE_UP.

Referenced by sla_station_exec().

03155 {
03156    struct sla_trunk_ref *trunk_ref = NULL;
03157 
03158    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03159       if (strcasecmp(trunk_ref->trunk->name, name))
03160          continue;
03161 
03162       if ( (trunk_ref->trunk->barge_disabled 
03163          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
03164          (trunk_ref->trunk->hold_stations 
03165          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
03166          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
03167          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
03168       {
03169          trunk_ref = NULL;
03170       }
03171 
03172       break;
03173    }
03174 
03175    return trunk_ref;
03176 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 3386 of file app_meetme.c.

References ALL_TRUNK_REFS, ast_answer(), ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), 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_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_background, ast_conference::attr, run_station_args::cond, run_station_args::cond_lock, free, LOG_DEBUG, 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().

03387 {
03388    struct sla_ringing_station *ringing_station;
03389 
03390    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03391       struct sla_trunk_ref *s_trunk_ref = NULL;
03392       struct sla_ringing_trunk *ringing_trunk = NULL;
03393       struct run_station_args args;
03394       enum ast_dial_result dial_res;
03395       pthread_attr_t attr;
03396       pthread_t dont_care;
03397       ast_mutex_t cond_lock;
03398       ast_cond_t cond;
03399 
03400       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
03401       case AST_DIAL_RESULT_HANGUP:
03402       case AST_DIAL_RESULT_INVALID:
03403       case AST_DIAL_RESULT_FAILED:
03404       case AST_DIAL_RESULT_TIMEOUT:
03405       case AST_DIAL_RESULT_UNANSWERED:
03406          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03407          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
03408          break;
03409       case AST_DIAL_RESULT_ANSWERED:
03410          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03411          /* Find the appropriate trunk to answer. */
03412          ast_mutex_lock(&sla.lock);
03413          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
03414          ast_mutex_unlock(&sla.lock);
03415          if (!ringing_trunk) {
03416             ast_log(LOG_DEBUG, "Found no ringing trunk for station '%s' to answer!\n",
03417                ringing_station->station->name);
03418             break;
03419          }
03420          /* Track the channel that answered this trunk */
03421          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
03422          /* Actually answer the trunk */
03423          ast_answer(ringing_trunk->trunk->chan);
03424          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
03425          /* Now, start a thread that will connect this station to the trunk.  The rest of
03426           * the code here sets up the thread and ensures that it is able to save the arguments
03427           * before they are no longer valid since they are allocated on the stack. */
03428          args.trunk_ref = s_trunk_ref;
03429          args.station = ringing_station->station;
03430          args.cond = &cond;
03431          args.cond_lock = &cond_lock;
03432          free(ringing_trunk);
03433          free(ringing_station);
03434          ast_mutex_init(&cond_lock);
03435          ast_cond_init(&cond, NULL);
03436          pthread_attr_init(&attr);
03437          pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
03438          ast_mutex_lock(&cond_lock);
03439          ast_pthread_create_background(&dont_care, &attr, run_station, &args);
03440          ast_cond_wait(&cond, &cond_lock);
03441          ast_mutex_unlock(&cond_lock);
03442          ast_mutex_destroy(&cond_lock);
03443          ast_cond_destroy(&cond);
03444          pthread_attr_destroy(&attr);
03445          break;
03446       case AST_DIAL_RESULT_TRYING:
03447       case AST_DIAL_RESULT_RINGING:
03448       case AST_DIAL_RESULT_PROGRESS:
03449       case AST_DIAL_RESULT_PROCEEDING:
03450          break;
03451       }
03452       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
03453          /* Queue up reprocessing ringing trunks, and then ringing stations again */
03454          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
03455          sla_queue_event(SLA_EVENT_DIAL_STATE);
03456          break;
03457       }
03458    }
03459    AST_LIST_TRAVERSE_SAFE_END
03460 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 3708 of file app_meetme.c.

References AST_CAUSE_NORMAL, AST_CONTROL_HOLD, ast_device_state_changed(), ast_indicate(), ast_softhangup(), INACTIVE_TRUNK_REFS, sla_change_trunk_state(), SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, sla_event::station, and sla_event::trunk_ref.

Referenced by sla_thread().

03709 {
03710    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
03711    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
03712    ast_device_state_changed("SLA:%s_%s", 
03713       event->station->name, event->trunk_ref->trunk->name);
03714    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
03715       INACTIVE_TRUNK_REFS, event->trunk_ref);
03716 
03717    if (event->trunk_ref->trunk->active_stations == 1) {
03718       /* The station putting it on hold is the only one on the call, so start
03719        * Music on hold to the trunk. */
03720       event->trunk_ref->trunk->on_hold = 1;
03721       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
03722    }
03723 
03724    ast_softhangup(event->trunk_ref->chan, AST_CAUSE_NORMAL);
03725    event->trunk_ref->chan = NULL;
03726 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 3698 of file app_meetme.c.

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

Referenced by sla_thread().

03699 {
03700    ast_mutex_lock(&sla.lock);
03701    sla_ring_stations();
03702    ast_mutex_unlock(&sla.lock);
03703 
03704    /* Find stations that shouldn't be ringing anymore. */
03705    sla_hangup_stations();
03706 }

static void sla_hangup_stations ( void   )  [static]

Definition at line 3670 of file app_meetme.c.

References ast_dial_destroy(), ast_dial_join(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_lock(), ast_mutex_unlock(), free, sla, sla_ringing_station::station, and sla_ringing_trunk::trunk.

Referenced by sla_handle_ringing_trunk_event().

03671 {
03672    struct sla_trunk_ref *trunk_ref;
03673    struct sla_ringing_station *ringing_station;
03674 
03675    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03676       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03677          struct sla_ringing_trunk *ringing_trunk;
03678          ast_mutex_lock(&sla.lock);
03679          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03680             if (trunk_ref->trunk == ringing_trunk->trunk)
03681                break;
03682          }
03683          ast_mutex_unlock(&sla.lock);
03684          if (ringing_trunk)
03685             break;
03686       }
03687       if (!trunk_ref) {
03688          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03689          ast_dial_join(ringing_station->station->dial);
03690          ast_dial_destroy(ringing_station->station->dial);
03691          ringing_station->station->dial = NULL;
03692          free(ringing_station);
03693       }
03694    }
03695    AST_LIST_TRAVERSE_SAFE_END
03696 }

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

Definition at line 1034 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01035 {
01036    const char *hold = "Unknown";
01037 
01038    switch (hold_access) {
01039    case SLA_HOLD_OPEN:
01040       hold = "Open";
01041       break;
01042    case SLA_HOLD_PRIVATE:
01043       hold = "Private";
01044    default:
01045       break;
01046    }
01047 
01048    return hold;
01049 }

static int sla_load_config ( void   )  [static]

Definition at line 4715 of file app_meetme.c.

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

Referenced by load_config().

04716 {
04717    struct ast_config *cfg;
04718    const char *cat = NULL;
04719    int res = 0;
04720    const char *val;
04721 
04722    ast_mutex_init(&sla.lock);
04723    ast_cond_init(&sla.cond, NULL);
04724 
04725    if (!(cfg = ast_config_load(SLA_CONFIG_FILE)))
04726       return 0; /* Treat no config as normal */
04727 
04728    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
04729       sla.attempt_callerid = ast_true(val);
04730 
04731    while ((cat = ast_category_browse(cfg, cat)) && !res) {
04732       const char *type;
04733       if (!strcasecmp(cat, "general"))
04734          continue;
04735       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
04736          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
04737             SLA_CONFIG_FILE);
04738          continue;
04739       }
04740       if (!strcasecmp(type, "trunk"))
04741          res = sla_build_trunk(cfg, cat);
04742       else if (!strcasecmp(type, "station"))
04743          res = sla_build_station(cfg, cat);
04744       else {
04745          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
04746             SLA_CONFIG_FILE, type);
04747       }
04748    }
04749 
04750    ast_config_destroy(cfg);
04751 
04752    ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
04753 
04754    return res;
04755 }

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

References ast_tvadd(), 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().

03887 {
03888    unsigned int timeout = UINT_MAX;
03889    struct timeval tv;
03890    unsigned int change_made = 0;
03891 
03892    /* Check for ring timeouts on ringing trunks */
03893    if (sla_calc_trunk_timeouts(&timeout))
03894       change_made = 1;
03895 
03896    /* Check for ring timeouts on ringing stations */
03897    if (sla_calc_station_timeouts(&timeout))
03898       change_made = 1;
03899 
03900    /* Check for station ring delays */
03901    if (sla_calc_station_delays(&timeout))
03902       change_made = 1;
03903 
03904    /* queue reprocessing of ringing trunks */
03905    if (change_made)
03906       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
03907 
03908    /* No timeout */
03909    if (timeout == UINT_MAX)
03910       return 0;
03911 
03912    if (ts) {
03913       tv = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
03914       ts->tv_sec = tv.tv_sec;
03915       ts->tv_nsec = tv.tv_usec * 1000;
03916    }
03917 
03918    return 1;
03919 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

Definition at line 1304 of file app_meetme.c.

References sla_queue_event_full().

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

01305 {
01306    sla_queue_event_full(type, NULL, NULL, 1);
01307 }

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

References AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdupa, ast_strlen_zero(), ast_conference::confno, LOG_DEBUG, LOG_ERROR, sla_queue_event_full(), and strsep().

Referenced by conf_run().

01312 {
01313    struct sla_station *station;
01314    struct sla_trunk_ref *trunk_ref = NULL;
01315    char *trunk_name;
01316 
01317    trunk_name = ast_strdupa(conf->confno);
01318    strsep(&trunk_name, "_");
01319    if (ast_strlen_zero(trunk_name)) {
01320       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01321       return;
01322    }
01323 
01324    AST_RWLIST_RDLOCK(&sla_stations);
01325    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01326       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01327          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01328             break;
01329       }
01330       if (trunk_ref)
01331          break;
01332    }
01333    AST_RWLIST_UNLOCK(&sla_stations);
01334 
01335    if (!trunk_ref) {
01336       ast_log(LOG_DEBUG, "Trunk not found for event!\n");
01337       return;
01338    }
01339 
01340    sla_queue_event_full(type, trunk_ref, station, 1);
01341 }

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

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

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

01278 {
01279    struct sla_event *event;
01280 
01281    if (!(event = ast_calloc(1, sizeof(*event))))
01282       return;
01283 
01284    event->type = type;
01285    event->trunk_ref = trunk_ref;
01286    event->station = station;
01287 
01288    if (!lock) {
01289       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01290       return;
01291    }
01292 
01293    ast_mutex_lock(&sla.lock);
01294    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01295    ast_cond_signal(&sla.cond);
01296    ast_mutex_unlock(&sla.lock);
01297 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1299 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01300 {
01301    sla_queue_event_full(type, NULL, NULL, 0);
01302 }

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

References ast_calloc, ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_TRYING, ast_dial_run(), ast_dial_set_state_callback(), AST_LIST_INSERT_HEAD, ast_strdup, ast_strdupa, ast_strlen_zero(), cid_name, cid_num, free, 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().

03504 {
03505    char *tech, *tech_data;
03506    struct ast_dial *dial;
03507    struct sla_ringing_station *ringing_station;
03508    const char *cid_name = NULL, *cid_num = NULL;
03509    enum ast_dial_result res;
03510 
03511    if (!(dial = ast_dial_create()))
03512       return -1;
03513 
03514    ast_dial_set_state_callback(dial, sla_dial_state_callback);
03515    tech_data = ast_strdupa(station->device);
03516    tech = strsep(&tech_data, "/");
03517 
03518    if (ast_dial_append(dial, tech, tech_data) == -1) {
03519       ast_dial_destroy(dial);
03520       return -1;
03521    }
03522 
03523    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
03524       cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
03525       free(ringing_trunk->trunk->chan->cid.cid_name);
03526       ringing_trunk->trunk->chan->cid.cid_name = NULL;
03527    }
03528    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
03529       cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
03530       free(ringing_trunk->trunk->chan->cid.cid_num);
03531       ringing_trunk->trunk->chan->cid.cid_num = NULL;
03532    }
03533 
03534    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
03535    
03536    if (cid_name)
03537       ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
03538    if (cid_num)
03539       ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
03540    
03541    if (res != AST_DIAL_RESULT_TRYING) {
03542       struct sla_failed_station *failed_station;
03543       ast_dial_destroy(dial);
03544       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
03545          return -1;
03546       failed_station->station = station;
03547       failed_station->last_try = ast_tvnow();
03548       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
03549       return -1;
03550    }
03551    if (!(ringing_station = sla_create_ringing_station(station))) {
03552       ast_dial_join(dial);
03553       ast_dial_destroy(dial);
03554       return -1;
03555    }
03556 
03557    station->dial = dial;
03558 
03559    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
03560 
03561    return 0;
03562 }

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 3629 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(), and sla_ringing_trunk::trunk.

Referenced by sla_handle_ringing_trunk_event().

03630 {
03631    struct sla_station_ref *station_ref;
03632    struct sla_ringing_trunk *ringing_trunk;
03633 
03634    /* Make sure that every station that uses at least one of the ringing
03635     * trunks, is ringing. */
03636    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03637       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
03638          int time_left;
03639 
03640          /* Is this station already ringing? */
03641          if (sla_check_ringing_station(station_ref->station))
03642             continue;
03643 
03644          /* Is this station already in a call? */
03645          if (sla_check_inuse_station(station_ref->station))
03646             continue;
03647 
03648          /* Did we fail to dial this station earlier?  If so, has it been
03649           * a minute since we tried? */
03650          if (sla_check_failed_station(station_ref->station))
03651             continue;
03652 
03653          /* If this station already timed out while this trunk was ringing,
03654           * do not dial it again for this ringing trunk. */
03655          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
03656             continue;
03657 
03658          /* Check for a ring delay in progress */
03659          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
03660          if (time_left != INT_MAX && time_left > 0)
03661             continue;
03662 
03663          /* It is time to make this station begin to ring.  Do it! */
03664          sla_ring_station(ringing_trunk, station_ref->station);
03665       }
03666    }
03667    /* Now, all of the stations that should be ringing, are ringing. */
03668 }

static int sla_show_stations ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 1111 of file app_meetme.c.

References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, RESULT_SUCCESS, S_OR, sla_hold_str(), and trunkstate2str().

01112 {
01113    const struct sla_station *station;
01114 
01115    ast_cli(fd, "\n" 
01116                "=============================================================\n"
01117                "=== Configured SLA Stations =================================\n"
01118                "=============================================================\n"
01119                "===\n");
01120    AST_RWLIST_RDLOCK(&sla_stations);
01121    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01122       struct sla_trunk_ref *trunk_ref;
01123       char ring_timeout[16] = "(none)";
01124       char ring_delay[16] = "(none)";
01125       if (station->ring_timeout) {
01126          snprintf(ring_timeout, sizeof(ring_timeout), 
01127             "%u", station->ring_timeout);
01128       }
01129       if (station->ring_delay) {
01130          snprintf(ring_delay, sizeof(ring_delay), 
01131             "%u", station->ring_delay);
01132       }
01133       ast_cli(fd, "=== ---------------------------------------------------------\n"
01134                   "=== Station Name:    %s\n"
01135                   "=== ==> Device:      %s\n"
01136                   "=== ==> AutoContext: %s\n"
01137                   "=== ==> RingTimeout: %s\n"
01138                   "=== ==> RingDelay:   %s\n"
01139                   "=== ==> HoldAccess:  %s\n"
01140                   "=== ==> Trunks ...\n",
01141                   station->name, station->device,
01142                   S_OR(station->autocontext, "(none)"), 
01143                   ring_timeout, ring_delay,
01144                   sla_hold_str(station->hold_access));
01145       AST_RWLIST_RDLOCK(&sla_trunks);
01146       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01147          if (trunk_ref->ring_timeout) {
01148             snprintf(ring_timeout, sizeof(ring_timeout),
01149                "%u", trunk_ref->ring_timeout);
01150          } else
01151             strcpy(ring_timeout, "(none)");
01152          if (trunk_ref->ring_delay) {
01153             snprintf(ring_delay, sizeof(ring_delay),
01154                "%u", trunk_ref->ring_delay);
01155          } else
01156             strcpy(ring_delay, "(none)");
01157          ast_cli(fd, "===    ==> Trunk Name: %s\n"
01158                      "===       ==> State:       %s\n"
01159                      "===       ==> RingTimeout: %s\n"
01160                      "===       ==> RingDelay:   %s\n",
01161                      trunk_ref->trunk->name,
01162                      trunkstate2str(trunk_ref->state),
01163                      ring_timeout, ring_delay);
01164       }
01165       AST_RWLIST_UNLOCK(&sla_trunks);
01166       ast_cli(fd, "=== ---------------------------------------------------------\n"
01167                   "===\n");
01168    }
01169    AST_RWLIST_UNLOCK(&sla_stations);
01170    ast_cli(fd, "============================================================\n"
01171                "\n");
01172 
01173    return RESULT_SUCCESS;
01174 }

static int sla_show_trunks ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 1051 of file app_meetme.c.

References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, RESULT_SUCCESS, S_OR, and sla_hold_str().

01052 {
01053    const struct sla_trunk *trunk;
01054 
01055    ast_cli(fd, "\n"
01056                "=============================================================\n"
01057                "=== Configured SLA Trunks ===================================\n"
01058                "=============================================================\n"
01059                "===\n");
01060    AST_RWLIST_RDLOCK(&sla_trunks);
01061    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01062       struct sla_station_ref *station_ref;
01063       char ring_timeout[16] = "(none)";
01064       if (trunk->ring_timeout)
01065          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01066       ast_cli(fd, "=== ---------------------------------------------------------\n"
01067                   "=== Trunk Name:       %s\n"
01068                   "=== ==> Device:       %s\n"
01069                   "=== ==> AutoContext:  %s\n"
01070                   "=== ==> RingTimeout:  %s\n"
01071                   "=== ==> BargeAllowed: %s\n"
01072                   "=== ==> HoldAccess:   %s\n"
01073                   "=== ==> Stations ...\n",
01074                   trunk->name, trunk->device, 
01075                   S_OR(trunk->autocontext, "(none)"), 
01076                   ring_timeout,
01077                   trunk->barge_disabled ? "No" : "Yes",
01078                   sla_hold_str(trunk->hold_access));
01079       AST_RWLIST_RDLOCK(&sla_stations);
01080       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01081          ast_cli(fd, "===    ==> Station name: %s\n", station_ref->station->name);
01082       AST_RWLIST_UNLOCK(&sla_stations);
01083       ast_cli(fd, "=== ---------------------------------------------------------\n"
01084                   "===\n");
01085    }
01086    AST_RWLIST_UNLOCK(&sla_trunks);
01087    ast_cli(fd, "=============================================================\n"
01088                "\n");
01089 
01090    return RESULT_SUCCESS;
01091 }

static int sla_state ( const char *  data  )  [static]

Definition at line 4342 of file app_meetme.c.

References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_strdupa, LOG_ERROR, SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, and strsep().

Referenced by load_module().

04343 {
04344    char *buf, *station_name, *trunk_name;
04345    struct sla_station *station;
04346    struct sla_trunk_ref *trunk_ref;
04347    int res = AST_DEVICE_INVALID;
04348 
04349    trunk_name = buf = ast_strdupa(data);
04350    station_name = strsep(&trunk_name, "_");
04351 
04352    AST_RWLIST_RDLOCK(&sla_stations);
04353    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04354       if (strcasecmp(station_name, station->name))
04355          continue;
04356       AST_RWLIST_RDLOCK(&sla_trunks);
04357       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04358          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
04359             break;
04360       }
04361       if (!trunk_ref) {
04362          AST_RWLIST_UNLOCK(&sla_trunks);
04363          break;
04364       }
04365       switch (trunk_ref->state) {
04366       case SLA_TRUNK_STATE_IDLE:
04367          res = AST_DEVICE_NOT_INUSE;
04368          break;
04369       case SLA_TRUNK_STATE_RINGING:
04370          res = AST_DEVICE_RINGING;
04371          break;
04372       case SLA_TRUNK_STATE_UP:
04373          res = AST_DEVICE_INUSE;
04374          break;
04375       case SLA_TRUNK_STATE_ONHOLD:
04376       case SLA_TRUNK_STATE_ONHOLD_BYME:
04377          res = AST_DEVICE_ONHOLD;
04378          break;
04379       }
04380       AST_RWLIST_UNLOCK(&sla_trunks);
04381    }
04382    AST_RWLIST_UNLOCK(&sla_stations);
04383 
04384    if (res == AST_DEVICE_INVALID) {
04385       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
04386          trunk_name, station_name);
04387    }
04388 
04389    return res;
04390 }

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

Definition at line 4108 of file app_meetme.c.

References admin_exec(), ALL_TRUNK_REFS, ast_answer(), ast_autoservice_start(), ast_autoservice_stop(), ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), AST_CONTROL_UNHOLD, ast_device_state_changed(), ast_indicate(), ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_conference::attr, build_conf(), conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dial_trunk(), dispose_conf(), ast_flags::flags, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, MAX_CONFNUM, pbx_builtin_setvar_helper(), sla_change_trunk_state(), sla_choose_idle_trunk(), sla_find_station(), sla_find_trunk_ref_byname(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_UP, strsep(), and dial_trunk_args::trunk_ref.

Referenced by load_module().

04109 {
04110    char *station_name, *trunk_name;
04111    struct sla_station *station;
04112    struct sla_trunk_ref *trunk_ref = NULL;
04113    char conf_name[MAX_CONFNUM];
04114    struct ast_flags conf_flags = { 0 };
04115    struct ast_conference *conf;
04116 
04117    if (ast_strlen_zero(data)) {
04118       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04119       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04120       return 0;
04121    }
04122 
04123    trunk_name = ast_strdupa(data);
04124    station_name = strsep(&trunk_name, "_");
04125 
04126    if (ast_strlen_zero(station_name)) {
04127       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04128       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04129       return 0;
04130    }
04131 
04132    AST_RWLIST_RDLOCK(&sla_stations);
04133    station = sla_find_station(station_name);
04134    AST_RWLIST_UNLOCK(&sla_stations);
04135 
04136    if (!station) {
04137       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
04138       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04139       return 0;
04140    }
04141 
04142    AST_RWLIST_RDLOCK(&sla_trunks);
04143    if (!ast_strlen_zero(trunk_name)) {
04144       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
04145    } else
04146       trunk_ref = sla_choose_idle_trunk(station);
04147    AST_RWLIST_UNLOCK(&sla_trunks);
04148 
04149    if (!trunk_ref) {
04150       if (ast_strlen_zero(trunk_name))
04151          ast_log(LOG_NOTICE, "No trunks available for call.\n");
04152       else {
04153          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
04154             "'%s' due to access controls.\n", trunk_name);
04155       }
04156       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
04157       return 0;
04158    }
04159 
04160    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
04161       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
04162          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04163       else {
04164          trunk_ref->state = SLA_TRUNK_STATE_UP;
04165          ast_device_state_changed("SLA:%s_%s", station->name, trunk_ref->trunk->name);
04166       }
04167    }
04168 
04169    trunk_ref->chan = chan;
04170 
04171    if (!trunk_ref->trunk->chan) {
04172       ast_mutex_t cond_lock;
04173       ast_cond_t cond;
04174       pthread_t dont_care;
04175       pthread_attr_t attr;
04176       struct dial_trunk_args args = {
04177          .trunk_ref = trunk_ref,
04178          .station = station,
04179          .cond_lock = &cond_lock,
04180          .cond = &cond,
04181       };
04182       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04183       /* Create a thread to dial the trunk and dump it into the conference.
04184        * However, we want to wait until the trunk has been dialed and the
04185        * conference is created before continuing on here. */
04186       ast_autoservice_start(chan);
04187       ast_mutex_init(&cond_lock);
04188       ast_cond_init(&cond, NULL);
04189       pthread_attr_init(&attr);
04190       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04191       ast_mutex_lock(&cond_lock);
04192       ast_pthread_create_background(&dont_care, &attr, dial_trunk, &args);
04193       ast_cond_wait(&cond, &cond_lock);
04194       ast_mutex_unlock(&cond_lock);
04195       ast_mutex_destroy(&cond_lock);
04196       ast_cond_destroy(&cond);
04197       pthread_attr_destroy(&attr);
04198       ast_autoservice_stop(chan);
04199       if (!trunk_ref->trunk->chan) {
04200          ast_log(LOG_DEBUG, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
04201          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
04202          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04203          trunk_ref->chan = NULL;
04204          return 0;
04205       }
04206    }
04207 
04208    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
04209       trunk_ref->trunk->on_hold) {
04210       trunk_ref->trunk->on_hold = 0;
04211       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
04212       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04213    }
04214 
04215    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04216    ast_set_flag(&conf_flags, 
04217       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04218    ast_answer(chan);
04219    conf = build_conf(conf_name, "", "", 0, 0, 1);
04220    if (conf) {
04221       conf_run(chan, conf, conf_flags.flags, NULL);
04222       dispose_conf(conf);
04223       conf = NULL;
04224    }
04225    trunk_ref->chan = NULL;
04226    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04227       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04228       strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
04229       admin_exec(NULL, conf_name);
04230       trunk_ref->trunk->hold_stations = 0;
04231       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04232    }
04233    
04234    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
04235 
04236    return 0;
04237 }

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

Definition at line 3288 of file app_meetme.c.

References ast_dial_destroy(), ast_dial_join(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, free, sla, sla_create_station_ref(), SLA_STATION_HANGUP_NORMAL, sla_ringing_station::station, and sla_ringing_trunk::trunk.

Referenced by sla_calc_station_timeouts(), and sla_handle_dial_state_event().

03290 {
03291    struct sla_ringing_trunk *ringing_trunk;
03292    struct sla_trunk_ref *trunk_ref;
03293    struct sla_station_ref *station_ref;
03294 
03295    ast_dial_join(ringing_station->station->dial);
03296    ast_dial_destroy(ringing_station->station->dial);
03297    ringing_station->station->dial = NULL;
03298 
03299    if (hangup == SLA_STATION_HANGUP_NORMAL)
03300       goto done;
03301 
03302    /* If the station is being hung up because of a timeout, then add it to the
03303     * list of timed out stations on each of the ringing trunks.  This is so
03304     * that when doing further processing to figure out which stations should be
03305     * ringing, which trunk to answer, determining timeouts, etc., we know which
03306     * ringing trunks we should ignore. */
03307    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03308       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03309          if (ringing_trunk->trunk == trunk_ref->trunk)
03310             break;
03311       }
03312       if (!trunk_ref)
03313          continue;
03314       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
03315          continue;
03316       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
03317    }
03318 
03319 done:
03320    free(ringing_station);
03321 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 3273 of file app_meetme.c.

References admin_exec(), ALL_TRUNK_REFS, AST_LIST_REMOVE_HEAD, free, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by sla_calc_trunk_timeouts().

03274 {
03275    char buf[80];
03276    struct sla_station_ref *station_ref;
03277 
03278    snprintf(buf, sizeof(buf), "SLA_%s|K", ringing_trunk->trunk->name);
03279    admin_exec(NULL, buf);
03280    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03281 
03282    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
03283       free(station_ref);
03284 
03285    free(ringing_trunk);
03286 }

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

Definition at line 3921 of file app_meetme.c.

References ast_cond_timedwait(), ast_cond_wait(), AST_LIST_EMPTY, AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), event, free, sla, SLA_EVENT_DIAL_STATE, SLA_EVENT_HOLD, 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().

03922 {
03923    struct sla_failed_station *failed_station;
03924    struct sla_ringing_station *ringing_station;
03925 
03926    ast_mutex_lock(&sla.lock);
03927 
03928    while (!sla.stop) {
03929       struct sla_event *event;
03930       struct timespec ts = { 0, };
03931       unsigned int have_timeout = 0;
03932 
03933       if (AST_LIST_EMPTY(&sla.event_q)) {
03934          if ((have_timeout = sla_process_timers(&ts)))
03935             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
03936          else
03937             ast_cond_wait(&sla.cond, &sla.lock);
03938          if (sla.stop)
03939             break;
03940       }
03941 
03942       if (have_timeout)
03943          sla_process_timers(NULL);
03944 
03945       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
03946          ast_mutex_unlock(&sla.lock);
03947          switch (event->type) {
03948          case SLA_EVENT_HOLD:
03949             sla_handle_hold_event(event);
03950             break;
03951          case SLA_EVENT_DIAL_STATE:
03952             sla_handle_dial_state_event();
03953             break;
03954          case SLA_EVENT_RINGING_TRUNK:
03955             sla_handle_ringing_trunk_event();
03956             break;
03957          }
03958          free(event);
03959          ast_mutex_lock(&sla.lock);
03960       }
03961    }
03962 
03963    ast_mutex_unlock(&sla.lock);
03964 
03965    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
03966       free(ringing_station);
03967 
03968    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
03969       free(failed_station);
03970 
03971    return NULL;
03972 }

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

Definition at line 4272 of file app_meetme.c.

References ALL_TRUNK_REFS, AST_CONTROL_RINGING, 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, build_conf(), conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, dispose_conf(), ast_flags::flags, free, LOG_ERROR, MAX_CONFNUM, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), queue_ringing_trunk(), sla, sla_change_trunk_state(), SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by load_module().

04273 {
04274    const char *trunk_name = data;
04275    char conf_name[MAX_CONFNUM];
04276    struct ast_conference *conf;
04277    struct ast_flags conf_flags = { 0 };
04278    struct sla_trunk *trunk;
04279    struct sla_ringing_trunk *ringing_trunk;
04280 
04281    AST_RWLIST_RDLOCK(&sla_trunks);
04282    trunk = sla_find_trunk(trunk_name);
04283    AST_RWLIST_UNLOCK(&sla_trunks);
04284    if (!trunk) {
04285       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", trunk_name);
04286       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04287       return 0;
04288    }
04289    if (trunk->chan) {
04290       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
04291          trunk_name);
04292       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04293       return 0;
04294    }
04295    trunk->chan = chan;
04296 
04297    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
04298       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04299       return 0;
04300    }
04301 
04302    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_name);
04303    conf = build_conf(conf_name, "", "", 1, 1, 1);
04304    if (!conf) {
04305       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04306       return 0;
04307    }
04308    ast_set_flag(&conf_flags, 
04309       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF);
04310    ast_indicate(chan, AST_CONTROL_RINGING);
04311    conf_run(chan, conf, conf_flags.flags, NULL);
04312    dispose_conf(conf);
04313    conf = NULL;
04314    trunk->chan = NULL;
04315    trunk->on_hold = 0;
04316    
04317    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
04318       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
04319 
04320    /* Remove the entry from the list of ringing trunks if it is still there. */
04321    ast_mutex_lock(&sla.lock);
04322    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04323       if (ringing_trunk->trunk == trunk) {
04324          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
04325          break;
04326       }
04327    }
04328    AST_LIST_TRAVERSE_SAFE_END
04329    ast_mutex_unlock(&sla.lock);
04330    if (ringing_trunk) {
04331       sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04332       free(ringing_trunk);
04333       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
04334       /* Queue reprocessing of ringing trunks to make stations stop ringing
04335        * that shouldn't be ringing after this trunk stopped. */
04336       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04337    }
04338 
04339    return 0;
04340 }

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

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

01094 {
01095 #define S(e) case e: return # e;
01096    switch (state) {
01097    S(SLA_TRUNK_STATE_IDLE)
01098    S(SLA_TRUNK_STATE_RINGING)
01099    S(SLA_TRUNK_STATE_UP)
01100    S(SLA_TRUNK_STATE_ONHOLD)
01101    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01102    }
01103    return "Uknown State";
01104 #undef S
01105 }

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

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

00673 {
00674    tweak_volume(&user->listen, action);
00675    /* attempt to make the adjustment in the channel driver;
00676       if successful, don't adjust in the frame reading routine
00677    */
00678    if (!set_listen_volume(user, user->listen.desired))
00679       user->listen.actual = 0;
00680    else
00681       user->listen.actual = user->listen.desired;
00682 }

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

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

00661 {
00662    tweak_volume(&user->talk, action);
00663    /* attempt to make the adjustment in the channel driver;
00664       if successful, don't adjust in the frame reading routine
00665    */
00666    if (!set_talk_volume(user, user->talk.desired))
00667       user->talk.actual = 0;
00668    else
00669       user->talk.actual = user->talk.desired;
00670 }

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

Definition at line 625 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

00626 {
00627    switch (action) {
00628    case VOL_UP:
00629       switch (vol->desired) { 
00630       case 5:
00631          break;
00632       case 0:
00633          vol->desired = 2;
00634          break;
00635       case -2:
00636          vol->desired = 0;
00637          break;
00638       default:
00639          vol->desired++;
00640          break;
00641       }
00642       break;
00643    case VOL_DOWN:
00644       switch (vol->desired) {
00645       case -5:
00646          break;
00647       case 2:
00648          vol->desired = 0;
00649          break;
00650       case 0:
00651          vol->desired = -2;
00652          break;
00653       default:
00654          vol->desired--;
00655          break;
00656       }
00657    }
00658 }

static int unload_module ( void   )  [static]

Definition at line 4768 of file app_meetme.c.

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

04769 {
04770    int res = 0;
04771    
04772    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
04773    res = ast_manager_unregister("MeetmeMute");
04774    res |= ast_manager_unregister("MeetmeUnmute");
04775    res |= ast_unregister_application(app3);
04776    res |= ast_unregister_application(app2);
04777    res |= ast_unregister_application(app);
04778    res |= ast_unregister_application(slastation_app);
04779    res |= ast_unregister_application(slatrunk_app);
04780 
04781    ast_devstate_prov_del("Meetme");
04782    ast_devstate_prov_del("SLA");
04783 
04784    ast_module_user_hangup_all();
04785    
04786    sla_destroy();
04787 
04788    return res;
04789 }


Variable Documentation

const char* app = "MeetMe" [static]

Definition at line 200 of file app_meetme.c.

const char* app2 = "MeetMeCount" [static]

Definition at line 201 of file app_meetme.c.

const char* app3 = "MeetMeAdmin" [static]

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

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1180 of file app_meetme.c.

ast_cond_t cond

Definition at line 522 of file app_meetme.c.

Referenced by _macro_exec(), and ast_safe_sleep_conditional().

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

Definition at line 349 of file app_meetme.c.

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

const char* descrip [static]

Definition at line 212 of file app_meetme.c.

const char* descrip2 [static]

Definition at line 261 of file app_meetme.c.

const char* descrip3 [static]

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

ast_mutex_t lock

Definition at line 523 of file app_meetme.c.

char meetme_usage[] [static]

Initial value:

"Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
"       Executes a command for the conference or on a conferee\n"

Definition at line 1030 of file app_meetme.c.

struct { ... } sla [static]

A structure for data used by the sla thread.

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

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

Definition at line 467 of file app_meetme.c.

Referenced by destroy_station(), destroy_trunk(), sla_build_station(), and sla_build_trunk().

const char sla_show_stations_usage[] [static]

Initial value:

"Usage: sla show stations\n"
"       This will list all stations defined in sla.conf\n"

Definition at line 1176 of file app_meetme.c.

const char sla_show_trunks_usage[] [static]

Initial value:

"Usage: sla show trunks\n"
"       This will list all trunks defined in sla.conf\n"

Definition at line 1107 of file app_meetme.c.

const char* slastation_app = "SLAStation" [static]

Definition at line 203 of file app_meetme.c.

const char* slastation_desc [static]

Definition at line 292 of file app_meetme.c.

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

Definition at line 209 of file app_meetme.c.

const char* slatrunk_app = "SLATrunk" [static]

Definition at line 204 of file app_meetme.c.

const char* slatrunk_desc [static]

Definition at line 305 of file app_meetme.c.

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

Definition at line 210 of file app_meetme.c.

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

Definition at line 206 of file app_meetme.c.

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

Definition at line 207 of file app_meetme.c.

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

Definition at line 208 of file app_meetme.c.

pthread_t thread

The SLA thread ID

Definition at line 521 of file app_meetme.c.

Referenced by __schedule_action(), __unload_module(), ast_bridge_call_thread_launch(), find_idle_thread(), iax2_process_thread(), iax2_process_thread_cleanup(), iax2_show_threads(), launch_monitor_thread(), load_module(), socket_read(), and start_network_thread().


Generated on Wed Aug 15 01:24:33 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3