Mon Mar 31 07:38:29 2008

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_conferencebuild_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_refcreate_trunk_ref (struct sla_trunk *trunk)
static void destroy_station (struct sla_station *station)
static void destroy_trunk (struct sla_trunk *trunk)
static void * dial_trunk (void *data)
static int dispose_conf (struct ast_conference *conf)
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
static struct ast_conferencefind_conf_realtime (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
static struct ast_conf_userfind_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_trunkqueue_ringing_trunk (struct sla_trunk *trunk)
static void * recordthread (void *args)
static int reload (void)
static void reset_volumes (struct ast_conf_user *user)
static void * run_station (void *data)
static 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_refsla_choose_idle_trunk (const struct sla_station *station)
 For a given station, choose the highest priority idle trunk.
static struct sla_ringing_trunksla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int remove)
 Choose the highest priority ringing trunk for a station.
static struct sla_ringing_stationsla_create_ringing_station (struct sla_station *station)
static struct sla_station_refsla_create_station_ref (struct sla_station *station)
static void sla_destroy (void)
static void sla_dial_state_callback (struct ast_dial *dial)
static struct sla_stationsla_find_station (const char *name)
 Find an SLA station by name.
static struct sla_trunksla_find_trunk (const char *name)
 Find an SLA trunk by name.
static struct sla_trunk_refsla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk)
static struct sla_trunk_refsla_find_trunk_ref_byname (const struct sla_station *station, const char *name)
 Find a trunk reference on a station by name.
static void sla_handle_dial_state_event (void)
static void sla_handle_hold_event (struct sla_event *event)
static void sla_handle_ringing_trunk_event (void)
static void sla_hangup_stations (void)
static const char * sla_hold_str (unsigned int hold_access)
static int sla_load_config (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 314 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 315 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_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 2989 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

02990 {
02991    return meetmemute(s, m, 1);
02992 }

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

Definition at line 2994 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

02995 {
02996    return meetmemute(s, m, 0);
02997 }

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

The MeetMeadmin application.

Definition at line 2775 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(), ast_conference::chan, 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, and VOL_UP.

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

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

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]

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_PTHREADT_NULL, ast_request(), ast_set_read_format(), ast_set_write_format(), ast_verbose(), conf_map, ast_conference::confno, free, LOG_WARNING, option_verbose, and VERBOSE_PREFIX_3.

Referenced by 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    cnf->recordthread = AST_PTHREADT_NULL;
00762    ast_mutex_init(&cnf->recordthreadlock);
00763    ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00764    ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00765    ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00766 
00767    /* Setup a new zap conference */
00768    ztc.confno = -1;
00769    ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
00770    cnf->fd = open("/dev/zap/pseudo", O_RDWR);
00771    if (cnf->fd < 0 || ioctl(cnf->fd, ZT_SETCONF, &ztc)) {
00772       ast_log(LOG_WARNING, "Unable to open pseudo device\n");
00773       if (cnf->fd >= 0)
00774          close(cnf->fd);
00775       free(cnf);
00776       cnf = NULL;
00777       goto cnfout;
00778    }
00779 
00780    cnf->zapconf = ztc.confno;
00781 
00782    /* Setup a new channel for playback of audio files */
00783    cnf->chan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
00784    if (cnf->chan) {
00785       ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
00786       ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
00787       ztc.chan = 0;
00788       ztc.confno = cnf->zapconf;
00789       ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
00790       if (ioctl(cnf->chan->fds[0], ZT_SETCONF, &ztc)) {
00791          ast_log(LOG_WARNING, "Error setting conference\n");
00792          if (cnf->chan)
00793             ast_hangup(cnf->chan);
00794          else
00795             close(cnf->fd);
00796          free(cnf);
00797          cnf = NULL;
00798          goto cnfout;
00799       }
00800    }
00801 
00802    /* Fill the conference struct */
00803    cnf->start = time(NULL);
00804    cnf->isdynamic = dynamic ? 1 : 0;
00805    if (option_verbose > 2)
00806       ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
00807    AST_LIST_INSERT_HEAD(&confs, cnf, list);
00808 
00809    /* Reserve conference number in map */
00810    if ((sscanf(cnf->confno, "%d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
00811       conf_map[confno_int] = 1;
00812    
00813 cnfout:
00814    if (cnf)
00815       ast_atomic_fetchadd_int(&cnf->refcount, refcount);
00816 
00817    AST_LIST_UNLOCK(&confs);
00818 
00819    return cnf;
00820 }

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(), errno, 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 970 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.

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

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

The meetme() application.

Definition at line 2512 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(), ast_conference::chan, conf_map, conf_run(), 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, OPT_ARG_ARRAY_SIZE, ast_conference::pin, ast_conference::pinadmin, strsep(), and var.

Referenced by load_module().

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

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

Definition at line 1196 of file app_meetme.c.

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

Referenced by conf_run().

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

static int conf_free ( struct ast_conference conf  )  [static]

Definition at line 1227 of file app_meetme.c.

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

Referenced by dispose_conf().

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

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(), ast_conference::chan, enter, ENTER, ast_conference::fd, 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 1268 of file app_meetme.c.

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

Referenced by conf_run().

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

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

Definition at line 1368 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, app, 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_new(), ast_dsp_silence(), 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_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_PTHREADT_NULL, 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, ast_channel::audiohooks, careful_write(), ast_conf_user::chan, ast_conference::chan, 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, ENTER, errno, EVENT_FLAG_CALL, exitcontext, f, ast_conference::fd, ast_channel::fds, ast_frame::flags, ast_frame::frametype, ast_conference::lchan, ast_conference::listenlock, ast_conference::locked, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, manager_event(), ast_conference::markedusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, ast_channel::monitor, OPT_ARG_WAITMARKED, option_debug, ast_conference::origframe, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), ast_conference::playlock, ast_channel::rawwriteformat, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, s, set_talk_volume(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_channel::tech, timeout, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_conf_user::userflags, ast_conference::users, VERBOSE_PREFIX_4, VOL_UP, and ast_conference::zapconf.

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

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

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

The MeetmeCount application.

Definition at line 2461 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::chan, ast_conference::confno, dispose_conf(), find_conf(), LOG_WARNING, pbx_builtin_setvar_helper(), and ast_conference::users.

Referenced by load_module().

02462 {
02463    struct ast_module_user *u;
02464    int res = 0;
02465    struct ast_conference *conf;
02466    int count;
02467    char *localdata;
02468    char val[80] = "0"; 
02469    AST_DECLARE_APP_ARGS(args,
02470       AST_APP_ARG(confno);
02471       AST_APP_ARG(varname);
02472    );
02473 
02474    if (ast_strlen_zero(data)) {
02475       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
02476       return -1;
02477    }
02478 
02479    u = ast_module_user_add(chan);
02480    
02481    if (!(localdata = ast_strdupa(data))) {
02482       ast_module_user_remove(u);
02483       return -1;
02484    }
02485 
02486    AST_STANDARD_APP_ARGS(args, localdata);
02487    
02488    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
02489 
02490    if (conf) {
02491       count = conf->users;
02492       dispose_conf(conf);
02493       conf = NULL;
02494    } else
02495       count = 0;
02496 
02497    if (!ast_strlen_zero(args.varname)){
02498       /* have var so load it and exit */
02499       snprintf(val, sizeof(val), "%d",count);
02500       pbx_builtin_setvar_helper(chan, args.varname, val);
02501    } else {
02502       if (chan->_state != AST_STATE_UP)
02503          ast_answer(chan);
02504       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
02505    }
02506    ast_module_user_remove(u);
02507 
02508    return res;
02509 }

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

Definition at line 4279 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station().

04280 {
04281    struct sla_trunk_ref *trunk_ref;
04282 
04283    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
04284       return NULL;
04285 
04286    trunk_ref->trunk = trunk;
04287 
04288    return trunk_ref;
04289 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 4447 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_memory, ast_strlen_zero(), exten, free, PRIORITY_HINT, and sla_registrar.

Referenced by sla_destroy().

04448 {
04449    struct sla_trunk_ref *trunk_ref;
04450 
04451    if (!ast_strlen_zero(station->autocontext)) {
04452       AST_RWLIST_RDLOCK(&sla_trunks);
04453       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04454          char exten[AST_MAX_EXTENSION];
04455          char hint[AST_MAX_APP];
04456          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04457          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04458          ast_context_remove_extension(station->autocontext, exten, 
04459             1, sla_registrar);
04460          ast_context_remove_extension(station->autocontext, hint, 
04461             PRIORITY_HINT, sla_registrar);
04462       }
04463       AST_RWLIST_UNLOCK(&sla_trunks);
04464    }
04465 
04466    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
04467       free(trunk_ref);
04468 
04469    ast_string_field_free_memory(station);
04470    free(station);
04471 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 4433 of file app_meetme.c.

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

Referenced by sla_destroy().

04434 {
04435    struct sla_station_ref *station_ref;
04436 
04437    if (!ast_strlen_zero(trunk->autocontext))
04438       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
04439 
04440    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
04441       free(station_ref);
04442 
04443    ast_string_field_free_memory(trunk);
04444    free(trunk);
04445 }

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

Definition at line 3998 of file app_meetme.c.

References 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_strdup, ast_strdupa, ast_strlen_zero(), cid_name, cid_num, dial_trunk_args::cond, dial_trunk_args::cond_lock, free, MAX_CONFNUM, sla, strsep(), and dial_trunk_args::trunk_ref.

Referenced by sla_station_exec().

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

static int dispose_conf ( struct ast_conference conf  )  [static]

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

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

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]

Definition at line 2367 of file app_meetme.c.

References AST_APP_ARG, ast_app_getdata(), 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_variable_browse(), build_conf(), ast_conference::chan, CONFIG_FILE_NAME, ast_conference::confno, LOG_DEBUG, LOG_WARNING, parse(), ast_conference::pin, ast_conference::pinadmin, ast_conference::refcount, S_OR, and var.

Referenced by conf_exec(), and count_exec().

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

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]

Definition at line 2310 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_RECORDCONF, ast_conference::confno, LOG_WARNING, ast_conference::pin, ast_conference::pinadmin, ast_conference::refcount, and var.

Referenced by conf_exec().

02312 {
02313    struct ast_variable *var;
02314    struct ast_conference *cnf;
02315 
02316    /* Check first in the conference list */
02317    AST_LIST_LOCK(&confs);
02318    AST_LIST_TRAVERSE(&confs, cnf, list) {
02319       if (!strcmp(confno, cnf->confno)) 
02320          break;
02321    }
02322    if (cnf) {
02323       cnf->refcount += refcount;
02324    }
02325    AST_LIST_UNLOCK(&confs);
02326 
02327    if (!cnf) {
02328       char *pin = NULL, *pinadmin = NULL; /* For temp use */
02329       
02330       var = ast_load_realtime("meetme", "confno", confno, NULL);
02331 
02332       if (!var)
02333          return NULL;
02334 
02335       while (var) {
02336          if (!strcasecmp(var->name, "pin")) {
02337             pin = ast_strdupa(var->value);
02338          } else if (!strcasecmp(var->name, "adminpin")) {
02339             pinadmin = ast_strdupa(var->value);
02340          }
02341          var = var->next;
02342       }
02343       ast_variables_destroy(var);
02344       
02345       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount);
02346    }
02347 
02348    if (cnf) {
02349       if (confflags && !cnf->chan &&
02350           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
02351           ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
02352          ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
02353          ast_clear_flag(confflags, CONFFLAG_INTROUSER);
02354       }
02355       
02356       if (confflags && !cnf->chan &&
02357           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
02358          ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
02359          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
02360       }
02361    }
02362 
02363    return cnf;
02364 }

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

Definition at line 2758 of file app_meetme.c.

References AST_LIST_TRAVERSE, and ast_conf_user::user_no.

02759 {
02760    struct ast_conf_user *user = NULL;
02761    int cid;
02762    
02763    sscanf(callerident, "%i", &cid);
02764    if (conf && callerident) {
02765       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
02766          if (cid == user->user_no)
02767             return user;
02768       }
02769    }
02770    return NULL;
02771 }

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

References load_config_meetme(), and sla_load_config().

04803 {
04804    int res = 0;
04805 
04806    load_config_meetme();
04807    if (!reload)
04808       res = sla_load_config();
04809 
04810    return res;
04811 }

static void load_config_meetme ( void   )  [static]

Definition at line 3086 of file app_meetme.c.

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

Referenced by load_config().

03087 {
03088    struct ast_config *cfg;
03089    const char *val;
03090 
03091    audio_buffers = DEFAULT_AUDIO_BUFFERS;
03092 
03093    if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
03094       return;
03095 
03096    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03097       if ((sscanf(val, "%d", &audio_buffers) != 1)) {
03098          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03099          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03100       } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) {
03101          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03102             ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS);
03103          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03104       }
03105       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03106          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03107    }
03108 
03109    ast_config_destroy(cfg);
03110 }

static int load_module ( void   )  [static]

Definition at line 4836 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(), cli_meetme, conf_exec(), count_exec(), load_config(), meetmestate(), sla_state(), sla_station_exec(), and sla_trunk_exec().

04837 {
04838    int res = 0;
04839 
04840    res |= load_config(0);
04841 
04842    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
04843    res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 
04844                 action_meetmemute, "Mute a Meetme user");
04845    res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 
04846                 action_meetmeunmute, "Unmute a Meetme user");
04847    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
04848    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
04849    res |= ast_register_application(app, conf_exec, synopsis, descrip);
04850    res |= ast_register_application(slastation_app, sla_station_exec,
04851                slastation_synopsis, slastation_desc);
04852    res |= ast_register_application(slatrunk_app, sla_trunk_exec,
04853                slatrunk_synopsis, slatrunk_desc);
04854 
04855    res |= ast_devstate_prov_add("Meetme", meetmestate);
04856    res |= ast_devstate_prov_add("SLA", sla_state);
04857 
04858    return res;
04859 }

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

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

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

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

Definition at line 2928 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, s, and ast_conf_user::user_no.

Referenced by action_meetmemute(), and action_meetmeunmute().

02929 {
02930    struct ast_conference *conf;
02931    struct ast_conf_user *user;
02932    const char *confid = astman_get_header(m, "Meetme");
02933    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
02934    int userno;
02935 
02936    if (ast_strlen_zero(confid)) {
02937       astman_send_error(s, m, "Meetme conference not specified");
02938       return 0;
02939    }
02940 
02941    if (ast_strlen_zero(userid)) {
02942       astman_send_error(s, m, "Meetme user number not specified");
02943       return 0;
02944    }
02945 
02946    userno = strtoul(userid, &userid, 10);
02947 
02948    if (*userid) {
02949       astman_send_error(s, m, "Invalid user number");
02950       return 0;
02951    }
02952 
02953    /* Look in the conference list */
02954    AST_LIST_LOCK(&confs);
02955    AST_LIST_TRAVERSE(&confs, conf, list) {
02956       if (!strcmp(confid, conf->confno))
02957          break;
02958    }
02959 
02960    if (!conf) {
02961       AST_LIST_UNLOCK(&confs);
02962       astman_send_error(s, m, "Meetme conference does not exist");
02963       return 0;
02964    }
02965 
02966    AST_LIST_TRAVERSE(&conf->userlist, user, list)
02967       if (user->user_no == userno)
02968          break;
02969 
02970    if (!user) {
02971       AST_LIST_UNLOCK(&confs);
02972       astman_send_error(s, m, "User number not found");
02973       return 0;
02974    }
02975 
02976    if (mute)
02977       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
02978    else
02979       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);  /* request user unmuting */
02980 
02981    AST_LIST_UNLOCK(&confs);
02982 
02983    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);
02984 
02985    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
02986    return 0;
02987 }

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

Callback for devicestate providers.

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

03065 {
03066    struct ast_conference *conf;
03067 
03068    /* Find conference */
03069    AST_LIST_LOCK(&confs);
03070    AST_LIST_TRAVERSE(&confs, conf, list) {
03071       if (!strcmp(data, conf->confno))
03072          break;
03073    }
03074    AST_LIST_UNLOCK(&confs);
03075    if (!conf)
03076       return AST_DEVICE_INVALID;
03077 
03078 
03079    /* SKREP to fill */
03080    if (!conf->users)
03081       return AST_DEVICE_NOT_INUSE;
03082 
03083    return AST_DEVICE_INUSE;
03084 }

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

Definition at line 4291 of file app_meetme.c.

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

04292 {
04293    struct sla_ringing_trunk *ringing_trunk;
04294 
04295    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
04296       return NULL;
04297    
04298    ringing_trunk->trunk = trunk;
04299    ringing_trunk->ring_begin = ast_tvnow();
04300 
04301    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
04302 
04303    ast_mutex_lock(&sla.lock);
04304    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
04305    ast_mutex_unlock(&sla.lock);
04306 
04307    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04308 
04309    return ringing_trunk;
04310 }

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

Definition at line 2999 of file app_meetme.c.

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

03000 {
03001    struct ast_conference *cnf = args;
03002    struct ast_frame *f=NULL;
03003    int flags;
03004    struct ast_filestream *s=NULL;
03005    int res=0;
03006    int x;
03007    const char *oldrecordingfilename = NULL;
03008 
03009    if (!cnf || !cnf->lchan) {
03010       pthread_exit(0);
03011    }
03012 
03013    ast_stopstream(cnf->lchan);
03014    flags = O_CREAT|O_TRUNC|O_WRONLY;
03015 
03016 
03017    cnf->recording = MEETME_RECORD_ACTIVE;
03018    while (ast_waitfor(cnf->lchan, -1) > -1) {
03019       if (cnf->recording == MEETME_RECORD_TERMINATE) {
03020          AST_LIST_LOCK(&confs);
03021          AST_LIST_UNLOCK(&confs);
03022          break;
03023       }
03024       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
03025          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
03026          oldrecordingfilename = cnf->recordingfilename;
03027       }
03028       
03029       f = ast_read(cnf->lchan);
03030       if (!f) {
03031          res = -1;
03032          break;
03033       }
03034       if (f->frametype == AST_FRAME_VOICE) {
03035          ast_mutex_lock(&cnf->listenlock);
03036          for (x=0;x<AST_FRAME_BITS;x++) {
03037             /* Free any translations that have occured */
03038             if (cnf->transframe[x]) {
03039                ast_frfree(cnf->transframe[x]);
03040                cnf->transframe[x] = NULL;
03041             }
03042          }
03043          if (cnf->origframe)
03044             ast_frfree(cnf->origframe);
03045          cnf->origframe = ast_frdup(f);
03046          ast_mutex_unlock(&cnf->listenlock);
03047          if (s)
03048             res = ast_writestream(s, f);
03049          if (res) {
03050             ast_frfree(f);
03051             break;
03052          }
03053       }
03054       ast_frfree(f);
03055    }
03056    cnf->recording = MEETME_RECORD_OFF;
03057    if (s)
03058       ast_closestream(s);
03059    
03060    pthread_exit(0);
03061 }

static int reload ( void   )  [static]

Definition at line 4861 of file app_meetme.c.

References load_config().

04862 {
04863    return load_config(1);
04864 }

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

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

03246 {
03247    struct sla_station *station;
03248    struct sla_trunk_ref *trunk_ref;
03249    char conf_name[MAX_CONFNUM];
03250    struct ast_flags conf_flags = { 0 };
03251    struct ast_conference *conf;
03252 
03253    {
03254       struct run_station_args *args = data;
03255       station = args->station;
03256       trunk_ref = args->trunk_ref;
03257       ast_mutex_lock(args->cond_lock);
03258       ast_cond_signal(args->cond);
03259       ast_mutex_unlock(args->cond_lock);
03260       /* args is no longer valid here. */
03261    }
03262 
03263    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
03264    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
03265    ast_set_flag(&conf_flags, 
03266       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
03267    ast_answer(trunk_ref->chan);
03268    conf = build_conf(conf_name, "", "", 0, 0, 1);
03269    if (conf) {
03270       conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
03271       dispose_conf(conf);
03272       conf = NULL;
03273    }
03274    trunk_ref->chan = NULL;
03275    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
03276       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
03277       strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
03278       admin_exec(NULL, conf_name);
03279       trunk_ref->trunk->hold_stations = 0;
03280       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03281    }
03282 
03283    ast_dial_join(station->dial);
03284    ast_dial_destroy(station->dial);
03285    station->dial = NULL;
03286 
03287    return NULL;
03288 }

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 4594 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_WARNING, name, sla_create_station_ref(), SLA_TRUNK_STATE_IDLE, strsep(), and var.

Referenced by sla_build_station().

04595 {
04596    struct sla_trunk *trunk;
04597    struct sla_trunk_ref *trunk_ref;
04598    struct sla_station_ref *station_ref;
04599    char *trunk_name, *options, *cur;
04600 
04601    options = ast_strdupa(var->value);
04602    trunk_name = strsep(&options, ",");
04603    
04604    AST_RWLIST_RDLOCK(&sla_trunks);
04605    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04606       if (!strcasecmp(trunk->name, trunk_name))
04607          break;
04608    }
04609 
04610    AST_RWLIST_UNLOCK(&sla_trunks);
04611    if (!trunk) {
04612       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
04613       return;
04614    }
04615    if (!(trunk_ref = create_trunk_ref(trunk)))
04616       return;
04617    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
04618 
04619    while ((cur = strsep(&options, ","))) {
04620       char *name, *value = cur;
04621       name = strsep(&value, "=");
04622       if (!strcasecmp(name, "ringtimeout")) {
04623          if (sscanf(value, "%u", &trunk_ref->ring_timeout) != 1) {
04624             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
04625                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04626             trunk_ref->ring_timeout = 0;
04627          }
04628       } else if (!strcasecmp(name, "ringdelay")) {
04629          if (sscanf(value, "%u", &trunk_ref->ring_delay) != 1) {
04630             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
04631                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04632             trunk_ref->ring_delay = 0;
04633          }
04634       } else {
04635          ast_log(LOG_WARNING, "Invalid option '%s' for "
04636             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
04637       }
04638    }
04639 
04640    if (!(station_ref = sla_create_station_ref(station))) {
04641       free(trunk_ref);
04642       return;
04643    }
04644    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
04645    AST_RWLIST_WRLOCK(&sla_trunks);
04646    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
04647    AST_RWLIST_UNLOCK(&sla_trunks);
04648    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
04649 }

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

Definition at line 4651 of file app_meetme.c.

References ast_calloc, ast_log(), ast_string_field_init, ast_string_field_set, ast_variable_browse(), ast_variable_retrieve(), free, LOG_WARNING, name, sla_add_trunk_to_station(), and var.

Referenced by sla_load_config().

04652 {
04653    struct sla_station *station;
04654    struct ast_variable *var;
04655    const char *dev;
04656 
04657    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
04658       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
04659       return -1;
04660    }
04661 
04662    if (!(station = ast_calloc(1, sizeof(*station))))
04663       return -1;
04664    if (ast_string_field_init(station, 32)) {
04665       free(station);
04666       return -1;
04667    }
04668 
04669    ast_string_field_set(station, name, cat);
04670    ast_string_field_set(station, device, dev);
04671 
04672    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04673       if (!strcasecmp(var->name, "trunk"))
04674          sla_add_trunk_to_station(station, var);
04675       else if (!strcasecmp(var->name, "autocontext"))
04676          ast_string_field_set(station, autocontext, var->value);
04677       else if (!strcasecmp(var->name, "ringtimeout")) {
04678          if (sscanf(var->value, "%u", &station->ring_timeout) != 1) {
04679             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
04680                var->value, station->name);
04681             station->ring_timeout = 0;
04682          }
04683       } else if (!strcasecmp(var->name, "ringdelay")) {
04684          if (sscanf(var->value, "%u", &station->ring_delay) != 1) {
04685             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
04686                var->value, station->name);
04687             station->ring_delay = 0;
04688          }
04689       } else if (!strcasecmp(var->name, "hold")) {
04690          if (!strcasecmp(var->value, "private"))
04691             station->hold_access = SLA_HOLD_PRIVATE;
04692          else if (!strcasecmp(var->value, "open"))
04693             station->hold_access = SLA_HOLD_OPEN;
04694          else {
04695             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
04696                var->value, station->name);
04697          }
04698 
04699       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
04700          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
04701             var->name, var->lineno, SLA_CONFIG_FILE);
04702       }
04703    }
04704 
04705    if (!ast_strlen_zero(station->autocontext)) {
04706       struct ast_context *context;
04707       struct sla_trunk_ref *trunk_ref;
04708       context = ast_context_find_or_create(NULL, station->autocontext, sla_registrar);
04709       if (!context) {
04710          ast_log(LOG_ERROR, "Failed to automatically find or create "
04711             "context '%s' for SLA!\n", station->autocontext);
04712          destroy_station(station);
04713          return -1;
04714       }
04715       /* The extension for when the handset goes off-hook.
04716        * exten => station1,1,SLAStation(station1) */
04717       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
04718          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free, sla_registrar)) {
04719          ast_log(LOG_ERROR, "Failed to automatically create extension "
04720             "for trunk '%s'!\n", station->name);
04721          destroy_station(station);
04722          return -1;
04723       }
04724       AST_RWLIST_RDLOCK(&sla_trunks);
04725       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04726          char exten[AST_MAX_EXTENSION];
04727          char hint[AST_MAX_APP];
04728          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04729          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04730          /* Extension for this line button 
04731           * exten => station1_line1,1,SLAStation(station1_line1) */
04732          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
04733             NULL, NULL, slastation_app, ast_strdup(exten), ast_free, sla_registrar)) {
04734             ast_log(LOG_ERROR, "Failed to automatically create extension "
04735                "for trunk '%s'!\n", station->name);
04736             destroy_station(station);
04737             return -1;
04738          }
04739          /* Hint for this line button 
04740           * exten => station1_line1,hint,SLA:station1_line1 */
04741          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
04742             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
04743             ast_log(LOG_ERROR, "Failed to automatically create hint "
04744                "for trunk '%s'!\n", station->name);
04745             destroy_station(station);
04746             return -1;
04747          }
04748       }
04749       AST_RWLIST_UNLOCK(&sla_trunks);
04750    }
04751 
04752    AST_RWLIST_WRLOCK(&sla_stations);
04753    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
04754    AST_RWLIST_UNLOCK(&sla_stations);
04755 
04756    return 0;
04757 }

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

Definition at line 4516 of file app_meetme.c.

References ast_calloc, ast_log(), ast_string_field_init, ast_string_field_set, ast_variable_browse(), ast_variable_retrieve(), free, LOG_ERROR, LOG_WARNING, name, sla_check_device(), and var.

Referenced by sla_load_config().

04517 {
04518    struct sla_trunk *trunk;
04519    struct ast_variable *var;
04520    const char *dev;
04521 
04522    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
04523       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
04524       return -1;
04525    }
04526 
04527    if (sla_check_device(dev)) {
04528       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
04529          cat, dev);
04530       return -1;
04531    }
04532 
04533    if (!(trunk = ast_calloc(1, sizeof(*trunk))))
04534       return -1;
04535    if (ast_string_field_init(trunk, 32)) {
04536       free(trunk);
04537       return -1;
04538    }
04539 
04540    ast_string_field_set(trunk, name, cat);
04541    ast_string_field_set(trunk, device, dev);
04542 
04543    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04544       if (!strcasecmp(var->name, "autocontext"))
04545          ast_string_field_set(trunk, autocontext, var->value);
04546       else if (!strcasecmp(var->name, "ringtimeout")) {
04547          if (sscanf(var->value, "%u", &trunk->ring_timeout) != 1) {
04548             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
04549                var->value, trunk->name);
04550             trunk->ring_timeout = 0;
04551          }
04552       } else if (!strcasecmp(var->name, "barge"))
04553          trunk->barge_disabled = ast_false(var->value);
04554       else if (!strcasecmp(var->name, "hold")) {
04555          if (!strcasecmp(var->value, "private"))
04556             trunk->hold_access = SLA_HOLD_PRIVATE;
04557          else if (!strcasecmp(var->value, "open"))
04558             trunk->hold_access = SLA_HOLD_OPEN;
04559          else {
04560             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
04561                var->value, trunk->name);
04562          }
04563       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
04564          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
04565             var->name, var->lineno, SLA_CONFIG_FILE);
04566       }
04567    }
04568 
04569    if (!ast_strlen_zero(trunk->autocontext)) {
04570       struct ast_context *context;
04571       context = ast_context_find_or_create(NULL, trunk->autocontext, sla_registrar);
04572       if (!context) {
04573          ast_log(LOG_ERROR, "Failed to automatically find or create "
04574             "context '%s' for SLA!\n", trunk->autocontext);
04575          destroy_trunk(trunk);
04576          return -1;
04577       }
04578       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
04579          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free, sla_registrar)) {
04580          ast_log(LOG_ERROR, "Failed to automatically create extension "
04581             "for trunk '%s'!\n", trunk->name);
04582          destroy_trunk(trunk);
04583          return -1;
04584       }
04585    }
04586 
04587    AST_RWLIST_WRLOCK(&sla_trunks);
04588    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
04589    AST_RWLIST_UNLOCK(&sla_trunks);
04590 
04591    return 0;
04592 }

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

03863 {
03864    struct sla_station *station;
03865    int res = 0;
03866 
03867    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
03868       struct sla_ringing_trunk *ringing_trunk;
03869       int time_left;
03870 
03871       /* Ignore stations already ringing */
03872       if (sla_check_ringing_station(station))
03873          continue;
03874 
03875       /* Ignore stations already on a call */
03876       if (sla_check_inuse_station(station))
03877          continue;
03878 
03879       /* Ignore stations that don't have one of their trunks ringing */
03880       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
03881          continue;
03882 
03883       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
03884          continue;
03885 
03886       /* If there is no time left, then the station needs to start ringing.
03887        * Return non-zero so that an event will be queued up an event to 
03888        * make that happen. */
03889       if (time_left <= 0) {
03890          res = 1;
03891          continue;
03892       }
03893 
03894       if (time_left < *timeout)
03895          *timeout = time_left;
03896    }
03897 
03898    return res;
03899 }

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

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

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

03750 {
03751    struct sla_ringing_trunk *ringing_trunk;
03752    int res = 0;
03753 
03754    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03755       int time_left, time_elapsed;
03756       if (!ringing_trunk->trunk->ring_timeout)
03757          continue;
03758       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03759       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
03760       if (time_left <= 0) {
03761          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
03762          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03763          sla_stop_ringing_trunk(ringing_trunk);
03764          res = 1;
03765          continue;
03766       }
03767       if (time_left < *timeout)
03768          *timeout = time_left;
03769    }
03770    AST_LIST_TRAVERSE_SAFE_END
03771 
03772    return res;
03773 }

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

References ast_device_state_changed(), and AST_LIST_TRAVERSE.

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

03222 {
03223    struct sla_station *station;
03224    struct sla_trunk_ref *trunk_ref;
03225 
03226    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
03227       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03228          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
03229             || trunk_ref == exclude)
03230             continue;
03231          trunk_ref->state = state;
03232          ast_device_state_changed("SLA:%s_%s", station->name, trunk->name);
03233          break;
03234       }
03235    }
03236 }

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

Definition at line 4503 of file app_meetme.c.

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

Referenced by sla_build_trunk().

04504 {
04505    char *tech, *tech_data;
04506 
04507    tech_data = ast_strdupa(device);
04508    tech = strsep(&tech_data, "/");
04509 
04510    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
04511       return -1;
04512 
04513    return 0;
04514 }

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

03498 {
03499    struct sla_failed_station *failed_station;
03500    int res = 0;
03501 
03502    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
03503       if (station != failed_station->station)
03504          continue;
03505       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
03506          AST_LIST_REMOVE_CURRENT(&sla.failed_stations, entry);
03507          free(failed_station);
03508          break;
03509       }
03510       res = 1;
03511    }
03512    AST_LIST_TRAVERSE_SAFE_END
03513 
03514    return res;
03515 }

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

Check to see if a station is in use.

Definition at line 3583 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

03584 {
03585    struct sla_trunk_ref *trunk_ref;
03586 
03587    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03588       if (trunk_ref->chan)
03589          return 1;
03590    }
03591 
03592    return 0;
03593 }

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

03483 {
03484    struct sla_ringing_station *ringing_station;
03485 
03486    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
03487       if (station == ringing_station->station)
03488          return 1;
03489    }
03490 
03491    return 0;
03492 }

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

03615 {
03616    struct sla_trunk_ref *trunk_ref;
03617    unsigned int delay = UINT_MAX;
03618    int time_left, time_elapsed;
03619 
03620    if (!ringing_trunk)
03621       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
03622    else
03623       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
03624 
03625    if (!ringing_trunk || !trunk_ref)
03626       return delay;
03627 
03628    /* If this station has a ring delay specific to the highest priority
03629     * ringing trunk, use that.  Otherwise, use the ring delay specified
03630     * globally for the station. */
03631    delay = trunk_ref->ring_delay;
03632    if (!delay)
03633       delay = station->ring_delay;
03634    if (!delay)
03635       return INT_MAX;
03636 
03637    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03638    time_left = (delay * 1000) - time_elapsed;
03639 
03640    return time_left;
03641 }

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

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

03144 {
03145    struct sla_station_ref *station_ref;
03146    struct sla_trunk_ref *trunk_ref;
03147 
03148    /* For each station that has this call on hold, check for private hold. */
03149    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03150       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03151          if (trunk_ref->trunk != trunk || station_ref->station == station)
03152             continue;
03153          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03154             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03155             return 1;
03156          return 0;
03157       }
03158    }
03159 
03160    return 0;
03161 }

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

References AST_LIST_TRAVERSE.

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

03350 {
03351    struct sla_station_ref *timed_out_station;
03352 
03353    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
03354       if (station == timed_out_station->station)
03355          return 1;
03356    }
03357 
03358    return 0;
03359 }

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

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

Definition at line 4113 of file app_meetme.c.

References AST_LIST_TRAVERSE, and SLA_TRUNK_STATE_IDLE.

Referenced by sla_station_exec().

04114 {
04115    struct sla_trunk_ref *trunk_ref = NULL;
04116 
04117    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04118       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
04119          break;
04120    }
04121 
04122    return trunk_ref;
04123 }

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

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

03371 {
03372    struct sla_trunk_ref *s_trunk_ref;
03373    struct sla_ringing_trunk *ringing_trunk = NULL;
03374 
03375    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
03376       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03377          /* Make sure this is the trunk we're looking for */
03378          if (s_trunk_ref->trunk != ringing_trunk->trunk)
03379             continue;
03380 
03381          /* This trunk on the station is ringing.  But, make sure this station
03382           * didn't already time out while this trunk was ringing. */
03383          if (sla_check_timed_out_station(ringing_trunk, station))
03384             continue;
03385 
03386          if (remove)
03387             AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03388 
03389          if (trunk_ref)
03390             *trunk_ref = s_trunk_ref;
03391 
03392          break;
03393       }
03394       AST_LIST_TRAVERSE_SAFE_END
03395    
03396       if (ringing_trunk)
03397          break;
03398    }
03399 
03400    return ringing_trunk;
03401 }

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

Definition at line 3207 of file app_meetme.c.

References ast_calloc, and sla_ringing_station::station.

Referenced by sla_ring_station().

03208 {
03209    struct sla_ringing_station *ringing_station;
03210 
03211    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
03212       return NULL;
03213 
03214    ringing_station->station = station;
03215    ringing_station->ring_begin = ast_tvnow();
03216 
03217    return ringing_station;
03218 }

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

Definition at line 3195 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().

03196 {
03197    struct sla_station_ref *station_ref;
03198 
03199    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
03200       return NULL;
03201 
03202    station_ref->station = station;
03203 
03204    return station_ref;
03205 }

static void sla_destroy ( void   )  [static]

Definition at line 4473 of file app_meetme.c.

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

Referenced by unload_module().

04474 {
04475    struct sla_trunk *trunk;
04476    struct sla_station *station;
04477 
04478    AST_RWLIST_WRLOCK(&sla_trunks);
04479    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
04480       destroy_trunk(trunk);
04481    AST_RWLIST_UNLOCK(&sla_trunks);
04482 
04483    AST_RWLIST_WRLOCK(&sla_stations);
04484    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
04485       destroy_station(station);
04486    AST_RWLIST_UNLOCK(&sla_stations);
04487 
04488    if (sla.thread != AST_PTHREADT_NULL) {
04489       ast_mutex_lock(&sla.lock);
04490       sla.stop = 1;
04491       ast_cond_signal(&sla.cond);
04492       ast_mutex_unlock(&sla.lock);
04493       pthread_join(sla.thread, NULL);
04494    }
04495 
04496    /* Drop any created contexts from the dialplan */
04497    ast_context_destroy(NULL, sla_registrar);
04498 
04499    ast_mutex_destroy(&sla.lock);
04500    ast_cond_destroy(&sla.cond);
04501 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 3340 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

03341 {
03342    sla_queue_event(SLA_EVENT_DIAL_STATE);
03343 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 3130 of file app_meetme.c.

References AST_RWLIST_TRAVERSE.

Referenced by sla_station_exec().

03131 {
03132    struct sla_station *station = NULL;
03133 
03134    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03135       if (!strcasecmp(station->name, name))
03136          break;
03137    }
03138 
03139    return station;
03140 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 3115 of file app_meetme.c.

References AST_RWLIST_TRAVERSE.

Referenced by sla_trunk_exec().

03116 {
03117    struct sla_trunk *trunk = NULL;
03118 
03119    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03120       if (!strcasecmp(trunk->name, name))
03121          break;
03122    }
03123 
03124    return trunk;
03125 }

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

Definition at line 3595 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_check_station_delay().

03597 {
03598    struct sla_trunk_ref *trunk_ref = NULL;
03599 
03600    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03601       if (trunk_ref->trunk == trunk)
03602          break;
03603    }
03604 
03605    return trunk_ref;
03606 }

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

Find a trunk reference on a station by name.

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

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

03172 {
03173    struct sla_trunk_ref *trunk_ref = NULL;
03174 
03175    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03176       if (strcasecmp(trunk_ref->trunk->name, name))
03177          continue;
03178 
03179       if ( (trunk_ref->trunk->barge_disabled 
03180          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
03181          (trunk_ref->trunk->hold_stations 
03182          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
03183          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
03184          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
03185       {
03186          trunk_ref = NULL;
03187       }
03188 
03189       break;
03190    }
03191 
03192    return trunk_ref;
03193 }

static void sla_handle_dial_state_event ( void   )  [static]

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

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

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 3725 of file app_meetme.c.

References AST_CAUSE_NORMAL, AST_CONTROL_HOLD, ast_device_state_changed(), ast_indicate(), ast_softhangup(), event, INACTIVE_TRUNK_REFS, sla_change_trunk_state(), SLA_TRUNK_STATE_ONHOLD, and SLA_TRUNK_STATE_ONHOLD_BYME.

Referenced by sla_thread().

03726 {
03727    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
03728    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
03729    ast_device_state_changed("SLA:%s_%s", 
03730       event->station->name, event->trunk_ref->trunk->name);
03731    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
03732       INACTIVE_TRUNK_REFS, event->trunk_ref);
03733 
03734    if (event->trunk_ref->trunk->active_stations == 1) {
03735       /* The station putting it on hold is the only one on the call, so start
03736        * Music on hold to the trunk. */
03737       event->trunk_ref->trunk->on_hold = 1;
03738       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
03739    }
03740 
03741    ast_softhangup(event->trunk_ref->chan, AST_CAUSE_NORMAL);
03742    event->trunk_ref->chan = NULL;
03743 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 3715 of file app_meetme.c.

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

Referenced by sla_thread().

03716 {
03717    ast_mutex_lock(&sla.lock);
03718    sla_ring_stations();
03719    ast_mutex_unlock(&sla.lock);
03720 
03721    /* Find stations that shouldn't be ringing anymore. */
03722    sla_hangup_stations();
03723 }

static void sla_hangup_stations ( void   )  [static]

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

03688 {
03689    struct sla_trunk_ref *trunk_ref;
03690    struct sla_ringing_station *ringing_station;
03691 
03692    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03693       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03694          struct sla_ringing_trunk *ringing_trunk;
03695          ast_mutex_lock(&sla.lock);
03696          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03697             if (trunk_ref->trunk == ringing_trunk->trunk)
03698                break;
03699          }
03700          ast_mutex_unlock(&sla.lock);
03701          if (ringing_trunk)
03702             break;
03703       }
03704       if (!trunk_ref) {
03705          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03706          ast_dial_join(ringing_station->station->dial);
03707          ast_dial_destroy(ringing_station->station->dial);
03708          ringing_station->station->dial = NULL;
03709          free(ringing_station);
03710       }
03711    }
03712    AST_LIST_TRAVERSE_SAFE_END
03713 }

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

Definition at line 1036 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

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

static int sla_load_config ( void   )  [static]

Definition at line 4759 of file app_meetme.c.

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

Referenced by load_config().

04760 {
04761    struct ast_config *cfg;
04762    const char *cat = NULL;
04763    int res = 0;
04764    const char *val;
04765 
04766    ast_mutex_init(&sla.lock);
04767    ast_cond_init(&sla.cond, NULL);
04768 
04769    if (!(cfg = ast_config_load(SLA_CONFIG_FILE)))
04770       return 0; /* Treat no config as normal */
04771 
04772    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
04773       sla.attempt_callerid = ast_true(val);
04774 
04775    while ((cat = ast_category_browse(cfg, cat)) && !res) {
04776       const char *type;
04777       if (!strcasecmp(cat, "general"))
04778          continue;
04779       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
04780          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
04781             SLA_CONFIG_FILE);
04782          continue;
04783       }
04784       if (!strcasecmp(type, "trunk"))
04785          res = sla_build_trunk(cfg, cat);
04786       else if (!strcasecmp(type, "station"))
04787          res = sla_build_station(cfg, cat);
04788       else {
04789          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
04790             SLA_CONFIG_FILE, type);
04791       }
04792    }
04793 
04794    ast_config_destroy(cfg);
04795 
04796    if (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations))
04797       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
04798 
04799    return res;
04800 }

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

References ast_tvadd(), sla_calc_station_delays(), sla_calc_station_timeouts(), sla_calc_trunk_timeouts(), SLA_EVENT_RINGING_TRUNK, sla_queue_event_nolock(), and timeout.

Referenced by sla_thread().

03904 {
03905    unsigned int timeout = UINT_MAX;
03906    struct timeval tv;
03907    unsigned int change_made = 0;
03908 
03909    /* Check for ring timeouts on ringing trunks */
03910    if (sla_calc_trunk_timeouts(&timeout))
03911       change_made = 1;
03912 
03913    /* Check for ring timeouts on ringing stations */
03914    if (sla_calc_station_timeouts(&timeout))
03915       change_made = 1;
03916 
03917    /* Check for station ring delays */
03918    if (sla_calc_station_delays(&timeout))
03919       change_made = 1;
03920 
03921    /* queue reprocessing of ringing trunks */
03922    if (change_made)
03923       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
03924 
03925    /* No timeout */
03926    if (timeout == UINT_MAX)
03927       return 0;
03928 
03929    if (ts) {
03930       tv = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
03931       ts->tv_sec = tv.tv_sec;
03932       ts->tv_nsec = tv.tv_usec * 1000;
03933    }
03934 
03935    return 1;
03936 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

Definition at line 1309 of file app_meetme.c.

References sla_queue_event_full().

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

01310 {
01311    sla_queue_event_full(type, NULL, NULL, 1);
01312 }

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 1315 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::chan, ast_conference::confno, LOG_DEBUG, LOG_ERROR, sla_queue_event_full(), and strsep().

Referenced by conf_run().

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

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

References ast_calloc, ast_cond_signal(), AST_LIST_INSERT_TAIL, ast_mutex_lock(), ast_mutex_unlock(), event, sla, sla_event::station, and sla_event::trunk_ref.

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

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

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1304 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

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

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

Referenced by sla_ring_stations().

03521 {
03522    char *tech, *tech_data;
03523    struct ast_dial *dial;
03524    struct sla_ringing_station *ringing_station;
03525    const char *cid_name = NULL, *cid_num = NULL;
03526    enum ast_dial_result res;
03527 
03528    if (!(dial = ast_dial_create()))
03529       return -1;
03530 
03531    ast_dial_set_state_callback(dial, sla_dial_state_callback);
03532    tech_data = ast_strdupa(station->device);
03533    tech = strsep(&tech_data, "/");
03534 
03535    if (ast_dial_append(dial, tech, tech_data) == -1) {
03536       ast_dial_destroy(dial);
03537       return -1;
03538    }
03539 
03540    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
03541       cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
03542       free(ringing_trunk->trunk->chan->cid.cid_name);
03543       ringing_trunk->trunk->chan->cid.cid_name = NULL;
03544    }
03545    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
03546       cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
03547       free(ringing_trunk->trunk->chan->cid.cid_num);
03548       ringing_trunk->trunk->chan->cid.cid_num = NULL;
03549    }
03550 
03551    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
03552    
03553    if (cid_name)
03554       ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
03555    if (cid_num)
03556       ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
03557    
03558    if (res != AST_DIAL_RESULT_TRYING) {
03559       struct sla_failed_station *failed_station;
03560       ast_dial_destroy(dial);
03561       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
03562          return -1;
03563       failed_station->station = station;
03564       failed_station->last_try = ast_tvnow();
03565       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
03566       return -1;
03567    }
03568    if (!(ringing_station = sla_create_ringing_station(station))) {
03569       ast_dial_join(dial);
03570       ast_dial_destroy(dial);
03571       return -1;
03572    }
03573 
03574    station->dial = dial;
03575 
03576    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
03577 
03578    return 0;
03579 }

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

03647 {
03648    struct sla_station_ref *station_ref;
03649    struct sla_ringing_trunk *ringing_trunk;
03650 
03651    /* Make sure that every station that uses at least one of the ringing
03652     * trunks, is ringing. */
03653    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03654       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
03655          int time_left;
03656 
03657          /* Is this station already ringing? */
03658          if (sla_check_ringing_station(station_ref->station))
03659             continue;
03660 
03661          /* Is this station already in a call? */
03662          if (sla_check_inuse_station(station_ref->station))
03663             continue;
03664 
03665          /* Did we fail to dial this station earlier?  If so, has it been
03666           * a minute since we tried? */
03667          if (sla_check_failed_station(station_ref->station))
03668             continue;
03669 
03670          /* If this station already timed out while this trunk was ringing,
03671           * do not dial it again for this ringing trunk. */
03672          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
03673             continue;
03674 
03675          /* Check for a ring delay in progress */
03676          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
03677          if (time_left != INT_MAX && time_left > 0)
03678             continue;
03679 
03680          /* It is time to make this station begin to ring.  Do it! */
03681          sla_ring_station(ringing_trunk, station_ref->station);
03682       }
03683    }
03684    /* Now, all of the stations that should be ringing, are ringing. */
03685 }

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

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

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

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

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

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

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

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

04384 {
04385    char *buf, *station_name, *trunk_name;
04386    struct sla_station *station;
04387    struct sla_trunk_ref *trunk_ref;
04388    int res = AST_DEVICE_INVALID;
04389 
04390    trunk_name = buf = ast_strdupa(data);
04391    station_name = strsep(&trunk_name, "_");
04392 
04393    AST_RWLIST_RDLOCK(&sla_stations);
04394    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04395       if (strcasecmp(station_name, station->name))
04396          continue;
04397       AST_RWLIST_RDLOCK(&sla_trunks);
04398       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04399          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
04400             break;
04401       }
04402       if (!trunk_ref) {
04403          AST_RWLIST_UNLOCK(&sla_trunks);
04404          break;
04405       }
04406       switch (trunk_ref->state) {
04407       case SLA_TRUNK_STATE_IDLE:
04408          res = AST_DEVICE_NOT_INUSE;
04409          break;
04410       case SLA_TRUNK_STATE_RINGING:
04411          res = AST_DEVICE_RINGING;
04412          break;
04413       case SLA_TRUNK_STATE_UP:
04414          res = AST_DEVICE_INUSE;
04415          break;
04416       case SLA_TRUNK_STATE_ONHOLD:
04417       case SLA_TRUNK_STATE_ONHOLD_BYME:
04418          res = AST_DEVICE_ONHOLD;
04419          break;
04420       }
04421       AST_RWLIST_UNLOCK(&sla_trunks);
04422    }
04423    AST_RWLIST_UNLOCK(&sla_stations);
04424 
04425    if (res == AST_DEVICE_INVALID) {
04426       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
04427          trunk_name, station_name);
04428    }
04429 
04430    return res;
04431 }

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

Definition at line 4125 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_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_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_conference::attr, build_conf(), ast_conference::chan, cond, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_SLA_STATION, dial_trunk(), dispose_conf(), ast_flags::flags, free, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, MAX_CONFNUM, pbx_builtin_setvar_helper(), sla, sla_change_trunk_state(), sla_choose_idle_trunk(), SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_find_station(), sla_find_trunk_ref_byname(), sla_queue_event(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, dial_trunk_args::station, strsep(), sla_ringing_trunk::trunk, and dial_trunk_args::trunk_ref.

Referenced by load_module().

04126 {
04127    char *station_name, *trunk_name;
04128    struct sla_station *station;
04129    struct sla_trunk_ref *trunk_ref = NULL;
04130    char conf_name[MAX_CONFNUM];
04131    struct ast_flags conf_flags = { 0 };
04132    struct ast_conference *conf;
04133 
04134    if (ast_strlen_zero(data)) {
04135       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04136       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04137       return 0;
04138    }
04139 
04140    trunk_name = ast_strdupa(data);
04141    station_name = strsep(&trunk_name, "_");
04142 
04143    if (ast_strlen_zero(station_name)) {
04144       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04145       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04146       return 0;
04147    }
04148 
04149    AST_RWLIST_RDLOCK(&sla_stations);
04150    station = sla_find_station(station_name);
04151    AST_RWLIST_UNLOCK(&sla_stations);
04152 
04153    if (!station) {
04154       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
04155       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04156       return 0;
04157    }
04158 
04159    AST_RWLIST_RDLOCK(&sla_trunks);
04160    if (!ast_strlen_zero(trunk_name)) {
04161       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
04162    } else
04163       trunk_ref = sla_choose_idle_trunk(station);
04164    AST_RWLIST_UNLOCK(&sla_trunks);
04165 
04166    if (!trunk_ref) {
04167       if (ast_strlen_zero(trunk_name))
04168          ast_log(LOG_NOTICE, "No trunks available for call.\n");
04169       else {
04170          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
04171             "'%s' due to access controls.\n", trunk_name);
04172       }
04173       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
04174       return 0;
04175    }
04176 
04177    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
04178       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
04179          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04180       else {
04181          trunk_ref->state = SLA_TRUNK_STATE_UP;
04182          ast_device_state_changed("SLA:%s_%s", station->name, trunk_ref->trunk->name);
04183       }
04184    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
04185       struct sla_ringing_trunk *ringing_trunk;
04186 
04187       ast_mutex_lock(&sla.lock);
04188       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04189          if (ringing_trunk->trunk == trunk_ref->trunk) {
04190             AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
04191             break;
04192          }
04193       }
04194       AST_LIST_TRAVERSE_SAFE_END
04195       ast_mutex_unlock(&sla.lock);
04196 
04197       if (ringing_trunk) {
04198          ast_answer(ringing_trunk->trunk->chan);
04199          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04200 
04201          free(ringing_trunk);
04202 
04203          /* Queue up reprocessing ringing trunks, and then ringing stations again */
04204          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04205          sla_queue_event(SLA_EVENT_DIAL_STATE);
04206       }
04207    }
04208 
04209    trunk_ref->chan = chan;
04210 
04211    if (!trunk_ref->trunk->chan) {
04212       ast_mutex_t cond_lock;
04213       ast_cond_t cond;
04214       pthread_t dont_care;
04215       pthread_attr_t attr;
04216       struct dial_trunk_args args = {
04217          .trunk_ref = trunk_ref,
04218          .station = station,
04219          .cond_lock = &cond_lock,
04220          .cond = &cond,
04221       };
04222       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04223       /* Create a thread to dial the trunk and dump it into the conference.
04224        * However, we want to wait until the trunk has been dialed and the
04225        * conference is created before continuing on here. */
04226       ast_autoservice_start(chan);
04227       ast_mutex_init(&cond_lock);
04228       ast_cond_init(&cond, NULL);
04229       pthread_attr_init(&attr);
04230       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04231       ast_mutex_lock(&cond_lock);
04232       ast_pthread_create_background(&dont_care, &attr, dial_trunk, &args);
04233       ast_cond_wait(&cond, &cond_lock);
04234       ast_mutex_unlock(&cond_lock);
04235       ast_mutex_destroy(&cond_lock);
04236       ast_cond_destroy(&cond);
04237       pthread_attr_destroy(&attr);
04238       ast_autoservice_stop(chan);
04239       if (!trunk_ref->trunk->chan) {
04240          ast_log(LOG_DEBUG, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
04241          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
04242          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04243          trunk_ref->chan = NULL;
04244          return 0;
04245       }
04246    }
04247 
04248    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
04249       trunk_ref->trunk->on_hold) {
04250       trunk_ref->trunk->on_hold = 0;
04251       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
04252       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04253    }
04254 
04255    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04256    ast_set_flag(&conf_flags, 
04257       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04258    ast_answer(chan);
04259    conf = build_conf(conf_name, "", "", 0, 0, 1);
04260    if (conf) {
04261       conf_run(chan, conf, conf_flags.flags, NULL);
04262       dispose_conf(conf);
04263       conf = NULL;
04264    }
04265    trunk_ref->chan = NULL;
04266    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04267       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04268       strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
04269       admin_exec(NULL, conf_name);
04270       trunk_ref->trunk->hold_stations = 0;
04271       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04272    }
04273    
04274    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
04275 
04276    return 0;
04277 }

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

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

03307 {
03308    struct sla_ringing_trunk *ringing_trunk;
03309    struct sla_trunk_ref *trunk_ref;
03310    struct sla_station_ref *station_ref;
03311 
03312    ast_dial_join(ringing_station->station->dial);
03313    ast_dial_destroy(ringing_station->station->dial);
03314    ringing_station->station->dial = NULL;
03315 
03316    if (hangup == SLA_STATION_HANGUP_NORMAL)
03317       goto done;
03318 
03319    /* If the station is being hung up because of a timeout, then add it to the
03320     * list of timed out stations on each of the ringing trunks.  This is so
03321     * that when doing further processing to figure out which stations should be
03322     * ringing, which trunk to answer, determining timeouts, etc., we know which
03323     * ringing trunks we should ignore. */
03324    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03325       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03326          if (ringing_trunk->trunk == trunk_ref->trunk)
03327             break;
03328       }
03329       if (!trunk_ref)
03330          continue;
03331       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
03332          continue;
03333       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
03334    }
03335 
03336 done:
03337    free(ringing_station);
03338 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

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

03291 {
03292    char buf[80];
03293    struct sla_station_ref *station_ref;
03294 
03295    snprintf(buf, sizeof(buf), "SLA_%s|K", ringing_trunk->trunk->name);
03296    admin_exec(NULL, buf);
03297    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03298 
03299    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
03300       free(station_ref);
03301 
03302    free(ringing_trunk);
03303 }

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

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

Referenced by sla_load_config().

03939 {
03940    struct sla_failed_station *failed_station;
03941    struct sla_ringing_station *ringing_station;
03942 
03943    ast_mutex_lock(&sla.lock);
03944 
03945    while (!sla.stop) {
03946       struct sla_event *event;
03947       struct timespec ts = { 0, };
03948       unsigned int have_timeout = 0;
03949 
03950       if (AST_LIST_EMPTY(&sla.event_q)) {
03951          if ((have_timeout = sla_process_timers(&ts)))
03952             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
03953          else
03954             ast_cond_wait(&sla.cond, &sla.lock);
03955          if (sla.stop)
03956             break;
03957       }
03958 
03959       if (have_timeout)
03960          sla_process_timers(NULL);
03961 
03962       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
03963          ast_mutex_unlock(&sla.lock);
03964          switch (event->type) {
03965          case SLA_EVENT_HOLD:
03966             sla_handle_hold_event(event);
03967             break;
03968          case SLA_EVENT_DIAL_STATE:
03969             sla_handle_dial_state_event();
03970             break;
03971          case SLA_EVENT_RINGING_TRUNK:
03972             sla_handle_ringing_trunk_event();
03973             break;
03974          }
03975          free(event);
03976          ast_mutex_lock(&sla.lock);
03977       }
03978    }
03979 
03980    ast_mutex_unlock(&sla.lock);
03981 
03982    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
03983       free(ringing_station);
03984 
03985    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
03986       free(failed_station);
03987 
03988    return NULL;
03989 }

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

Definition at line 4312 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(), ast_conference::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_PASS_DTMF, 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().

04313 {
04314    const char *trunk_name = data;
04315    char conf_name[MAX_CONFNUM];
04316    struct ast_conference *conf;
04317    struct ast_flags conf_flags = { 0 };
04318    struct sla_trunk *trunk;
04319    struct sla_ringing_trunk *ringing_trunk;
04320 
04321    AST_RWLIST_RDLOCK(&sla_trunks);
04322    trunk = sla_find_trunk(trunk_name);
04323    AST_RWLIST_UNLOCK(&sla_trunks);
04324    if (!trunk) {
04325       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", trunk_name);
04326       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04327       return 0;
04328    }
04329    if (trunk->chan) {
04330       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
04331          trunk_name);
04332       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04333       return 0;
04334    }
04335    trunk->chan = chan;
04336 
04337    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
04338       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04339       return 0;
04340    }
04341 
04342    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_name);
04343    conf = build_conf(conf_name, "", "", 1, 1, 1);
04344    if (!conf) {
04345       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04346       return 0;
04347    }
04348    ast_set_flag(&conf_flags, 
04349       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF);
04350    ast_indicate(chan, AST_CONTROL_RINGING);
04351    conf_run(chan, conf, conf_flags.flags, NULL);
04352    dispose_conf(conf);
04353    conf = NULL;
04354    trunk->chan = NULL;
04355    trunk->on_hold = 0;
04356 
04357    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04358 
04359    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
04360       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
04361 
04362    /* Remove the entry from the list of ringing trunks if it is still there. */
04363    ast_mutex_lock(&sla.lock);
04364    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04365       if (ringing_trunk->trunk == trunk) {
04366          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
04367          break;
04368       }
04369    }
04370    AST_LIST_TRAVERSE_SAFE_END
04371    ast_mutex_unlock(&sla.lock);
04372    if (ringing_trunk) {
04373       free(ringing_trunk);
04374       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
04375       /* Queue reprocessing of ringing trunks to make stations stop ringing
04376        * that shouldn't be ringing after this trunk stopped. */
04377       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04378    }
04379 
04380    return 0;
04381 }

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

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

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

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, 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 4813 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(), cli_meetme, and sla_destroy().

04814 {
04815    int res = 0;
04816    
04817    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
04818    res = ast_manager_unregister("MeetmeMute");
04819    res |= ast_manager_unregister("MeetmeUnmute");
04820    res |= ast_unregister_application(app3);
04821    res |= ast_unregister_application(app2);
04822    res |= ast_unregister_application(app);
04823    res |= ast_unregister_application(slastation_app);
04824    res |= ast_unregister_application(slatrunk_app);
04825 
04826    ast_devstate_prov_del("Meetme");
04827    ast_devstate_prov_del("SLA");
04828 
04829    ast_module_user_hangup_all();
04830    
04831    sla_destroy();
04832 
04833    return res;
04834 }


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.

Referenced by load_config_meetme().

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1182 of file app_meetme.c.

Referenced by load_module(), and unload_module().

ast_cond_t cond

Definition at line 522 of file app_meetme.c.

Referenced by _macro_exec(), gosubif_exec(), sla_handle_dial_state_event(), and sla_station_exec().

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

const char* descrip3 [static]

Definition at line 268 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 1032 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_station_exec(), 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(), and sla_destroy().

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 1178 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 1109 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 291 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 304 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(), handle_deferred_full_frames(), iax2_process_thread(), iax2_process_thread_cleanup(), iax2_show_threads(), insert_idle_thread(), launch_monitor_thread(), load_module(), socket_process(), socket_read(), and start_network_thread().


Generated on Mon Mar 31 07:38:30 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1