Tue Nov 4 13:20:23 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 <sys/stat.h>
#include <sys/types.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"

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

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

#define CONF_SIZE   320

Definition at line 109 of file app_meetme.c.

Referenced by conf_run().

#define CONFIG_FILE_NAME   "meetme.conf"

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

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

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

Referenced by conf_exec().

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 88 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 87 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 76 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 81 of file app_meetme.c.

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

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

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

anonymous enum

Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_ARRAY_SIZE 

Definition at line 168 of file app_meetme.c.

00168      {
00169    OPT_ARG_WAITMARKED = 0,
00170    OPT_ARG_ARRAY_SIZE = 1,
00171 };

enum entrance_sound

Enumerator:
ENTER 
LEAVE 

Definition at line 97 of file app_meetme.c.

00097                     {
00098    ENTER,
00099    LEAVE
00100 };

enum recording_state

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

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

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

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

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

enum sla_station_hangup

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

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

enum sla_which_trunk_refs

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 373 of file app_meetme.c.

00373                           {
00374    ALL_TRUNK_REFS,
00375    INACTIVE_TRUNK_REFS,
00376 };

enum volume_action

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 92 of file app_meetme.c.

00092                    {
00093    VOL_UP,
00094    VOL_DOWN
00095 };


Function Documentation

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

Definition at line 3000 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03001 {
03002    return meetmemute(s, m, 1);
03003 }

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

Definition at line 3005 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03006 {
03007    return meetmemute(s, m, 0);
03008 }

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

The MeetMeadmin application.

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

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

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

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

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

Definition at line 576 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

Referenced by conf_play(), and conf_run().

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

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

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

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

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

The meetme() application.

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

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

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

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

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

static int conf_free ( struct ast_conference conf  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

The MeetmeCount application.

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

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

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

Definition at line 4290 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station().

04291 {
04292    struct sla_trunk_ref *trunk_ref;
04293 
04294    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
04295       return NULL;
04296 
04297    trunk_ref->trunk = trunk;
04298 
04299    return trunk_ref;
04300 }

static void destroy_station ( struct sla_station station  )  [static]

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

04459 {
04460    struct sla_trunk_ref *trunk_ref;
04461 
04462    if (!ast_strlen_zero(station->autocontext)) {
04463       AST_RWLIST_RDLOCK(&sla_trunks);
04464       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04465          char exten[AST_MAX_EXTENSION];
04466          char hint[AST_MAX_APP];
04467          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04468          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04469          ast_context_remove_extension(station->autocontext, exten, 
04470             1, sla_registrar);
04471          ast_context_remove_extension(station->autocontext, hint, 
04472             PRIORITY_HINT, sla_registrar);
04473       }
04474       AST_RWLIST_UNLOCK(&sla_trunks);
04475    }
04476 
04477    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
04478       free(trunk_ref);
04479 
04480    ast_string_field_free_memory(station);
04481    free(station);
04482 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

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

04445 {
04446    struct sla_station_ref *station_ref;
04447 
04448    if (!ast_strlen_zero(trunk->autocontext))
04449       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
04450 
04451    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
04452       free(station_ref);
04453 
04454    ast_string_field_free_memory(trunk);
04455    free(trunk);
04456 }

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

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

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

static int dispose_conf ( struct ast_conference conf  )  [static]

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

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

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

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

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

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

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

Definition at line 2769 of file app_meetme.c.

References AST_LIST_TRAVERSE, and ast_conf_user::user_no.

02770 {
02771    struct ast_conf_user *user = NULL;
02772    int cid;
02773    
02774    sscanf(callerident, "%i", &cid);
02775    if (conf && callerident) {
02776       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
02777          if (cid == user->user_no)
02778             return user;
02779       }
02780    }
02781    return NULL;
02782 }

static char* istalking ( int  x  )  [static]

Definition at line 566 of file app_meetme.c.

Referenced by meetme_cmd().

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

static int load_config ( int  reload  )  [static]

Definition at line 4813 of file app_meetme.c.

References load_config_meetme(), and sla_load_config().

04814 {
04815    int res = 0;
04816 
04817    load_config_meetme();
04818    if (!reload)
04819       res = sla_load_config();
04820 
04821    return res;
04822 }

static void load_config_meetme ( void   )  [static]

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

03098 {
03099    struct ast_config *cfg;
03100    const char *val;
03101 
03102    audio_buffers = DEFAULT_AUDIO_BUFFERS;
03103 
03104    if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
03105       return;
03106 
03107    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03108       if ((sscanf(val, "%d", &audio_buffers) != 1)) {
03109          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03110          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03111       } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) {
03112          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03113             ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS);
03114          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03115       }
03116       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03117          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03118    }
03119 
03120    ast_config_destroy(cfg);
03121 }

static int load_module ( void   )  [static]

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

04848 {
04849    int res = 0;
04850 
04851    res |= load_config(0);
04852 
04853    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
04854    res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 
04855                 action_meetmemute, "Mute a Meetme user");
04856    res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 
04857                 action_meetmeunmute, "Unmute a Meetme user");
04858    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
04859    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
04860    res |= ast_register_application(app, conf_exec, synopsis, descrip);
04861    res |= ast_register_application(slastation_app, sla_station_exec,
04862                slastation_synopsis, slastation_desc);
04863    res |= ast_register_application(slatrunk_app, sla_trunk_exec,
04864                slatrunk_synopsis, slatrunk_desc);
04865 
04866    res |= ast_devstate_prov_add("Meetme", meetmestate);
04867    res |= ast_devstate_prov_add("SLA", sla_state);
04868 
04869    return res;
04870 }

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

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

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

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

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

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

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

Callback for devicestate providers.

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

03076 {
03077    struct ast_conference *conf;
03078 
03079    /* Find conference */
03080    AST_LIST_LOCK(&confs);
03081    AST_LIST_TRAVERSE(&confs, conf, list) {
03082       if (!strcmp(data, conf->confno))
03083          break;
03084    }
03085    AST_LIST_UNLOCK(&confs);
03086    if (!conf)
03087       return AST_DEVICE_INVALID;
03088 
03089 
03090    /* SKREP to fill */
03091    if (!conf->users)
03092       return AST_DEVICE_NOT_INUSE;
03093 
03094    return AST_DEVICE_INUSE;
03095 }

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

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

04303 {
04304    struct sla_ringing_trunk *ringing_trunk;
04305 
04306    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
04307       return NULL;
04308    
04309    ringing_trunk->trunk = trunk;
04310    ringing_trunk->ring_begin = ast_tvnow();
04311 
04312    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
04313 
04314    ast_mutex_lock(&sla.lock);
04315    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
04316    ast_mutex_unlock(&sla.lock);
04317 
04318    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04319 
04320    return ringing_trunk;
04321 }

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

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

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

static int reload ( void   )  [static]

Definition at line 4872 of file app_meetme.c.

References load_config().

04873 {
04874    return load_config(1);
04875 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 686 of file app_meetme.c.

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

Referenced by admin_exec().

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

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

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

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

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

Definition at line 615 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

03761 {
03762    struct sla_ringing_trunk *ringing_trunk;
03763    int res = 0;
03764 
03765    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03766       int time_left, time_elapsed;
03767       if (!ringing_trunk->trunk->ring_timeout)
03768          continue;
03769       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03770       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
03771       if (time_left <= 0) {
03772          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
03773          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03774          sla_stop_ringing_trunk(ringing_trunk);
03775          res = 1;
03776          continue;
03777       }
03778       if (time_left < *timeout)
03779          *timeout = time_left;
03780    }
03781    AST_LIST_TRAVERSE_SAFE_END
03782 
03783    return res;
03784 }

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

03233 {
03234    struct sla_station *station;
03235    struct sla_trunk_ref *trunk_ref;
03236 
03237    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
03238       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03239          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
03240             || trunk_ref == exclude)
03241             continue;
03242          trunk_ref->state = state;
03243          ast_device_state_changed("SLA:%s_%s", station->name, trunk->name);
03244          break;
03245       }
03246    }
03247 }

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

Definition at line 4514 of file app_meetme.c.

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

Referenced by sla_build_trunk().

04515 {
04516    char *tech, *tech_data;
04517 
04518    tech_data = ast_strdupa(device);
04519    tech = strsep(&tech_data, "/");
04520 
04521    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
04522       return -1;
04523 
04524    return 0;
04525 }

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

03509 {
03510    struct sla_failed_station *failed_station;
03511    int res = 0;
03512 
03513    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
03514       if (station != failed_station->station)
03515          continue;
03516       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
03517          AST_LIST_REMOVE_CURRENT(&sla.failed_stations, entry);
03518          free(failed_station);
03519          break;
03520       }
03521       res = 1;
03522    }
03523    AST_LIST_TRAVERSE_SAFE_END
03524 
03525    return res;
03526 }

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

Check to see if a station is in use.

Definition at line 3594 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

03595 {
03596    struct sla_trunk_ref *trunk_ref;
03597 
03598    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03599       if (trunk_ref->chan)
03600          return 1;
03601    }
03602 
03603    return 0;
03604 }

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

03494 {
03495    struct sla_ringing_station *ringing_station;
03496 
03497    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
03498       if (station == ringing_station->station)
03499          return 1;
03500    }
03501 
03502    return 0;
03503 }

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

03626 {
03627    struct sla_trunk_ref *trunk_ref;
03628    unsigned int delay = UINT_MAX;
03629    int time_left, time_elapsed;
03630 
03631    if (!ringing_trunk)
03632       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
03633    else
03634       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
03635 
03636    if (!ringing_trunk || !trunk_ref)
03637       return delay;
03638 
03639    /* If this station has a ring delay specific to the highest priority
03640     * ringing trunk, use that.  Otherwise, use the ring delay specified
03641     * globally for the station. */
03642    delay = trunk_ref->ring_delay;
03643    if (!delay)
03644       delay = station->ring_delay;
03645    if (!delay)
03646       return INT_MAX;
03647 
03648    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03649    time_left = (delay * 1000) - time_elapsed;
03650 
03651    return time_left;
03652 }

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

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

03155 {
03156    struct sla_station_ref *station_ref;
03157    struct sla_trunk_ref *trunk_ref;
03158 
03159    /* For each station that has this call on hold, check for private hold. */
03160    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03161       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03162          if (trunk_ref->trunk != trunk || station_ref->station == station)
03163             continue;
03164          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03165             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03166             return 1;
03167          return 0;
03168       }
03169    }
03170 
03171    return 0;
03172 }

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

References AST_LIST_TRAVERSE.

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

03361 {
03362    struct sla_station_ref *timed_out_station;
03363 
03364    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
03365       if (station == timed_out_station->station)
03366          return 1;
03367    }
03368 
03369    return 0;
03370 }

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

References AST_LIST_TRAVERSE, and SLA_TRUNK_STATE_IDLE.

Referenced by sla_station_exec().

04125 {
04126    struct sla_trunk_ref *trunk_ref = NULL;
04127 
04128    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04129       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
04130          break;
04131    }
04132 
04133    return trunk_ref;
04134 }

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

03382 {
03383    struct sla_trunk_ref *s_trunk_ref;
03384    struct sla_ringing_trunk *ringing_trunk = NULL;
03385 
03386    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
03387       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03388          /* Make sure this is the trunk we're looking for */
03389          if (s_trunk_ref->trunk != ringing_trunk->trunk)
03390             continue;
03391 
03392          /* This trunk on the station is ringing.  But, make sure this station
03393           * didn't already time out while this trunk was ringing. */
03394          if (sla_check_timed_out_station(ringing_trunk, station))
03395             continue;
03396 
03397          if (remove)
03398             AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03399 
03400          if (trunk_ref)
03401             *trunk_ref = s_trunk_ref;
03402 
03403          break;
03404       }
03405       AST_LIST_TRAVERSE_SAFE_END
03406    
03407       if (ringing_trunk)
03408          break;
03409    }
03410 
03411    return ringing_trunk;
03412 }

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

Definition at line 3218 of file app_meetme.c.

References ast_calloc, and sla_ringing_station::station.

Referenced by sla_ring_station().

03219 {
03220    struct sla_ringing_station *ringing_station;
03221 
03222    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
03223       return NULL;
03224 
03225    ringing_station->station = station;
03226    ringing_station->ring_begin = ast_tvnow();
03227 
03228    return ringing_station;
03229 }

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

Definition at line 3206 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().

03207 {
03208    struct sla_station_ref *station_ref;
03209 
03210    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
03211       return NULL;
03212 
03213    station_ref->station = station;
03214 
03215    return station_ref;
03216 }

static void sla_destroy ( void   )  [static]

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

04485 {
04486    struct sla_trunk *trunk;
04487    struct sla_station *station;
04488 
04489    AST_RWLIST_WRLOCK(&sla_trunks);
04490    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
04491       destroy_trunk(trunk);
04492    AST_RWLIST_UNLOCK(&sla_trunks);
04493 
04494    AST_RWLIST_WRLOCK(&sla_stations);
04495    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
04496       destroy_station(station);
04497    AST_RWLIST_UNLOCK(&sla_stations);
04498 
04499    if (sla.thread != AST_PTHREADT_NULL) {
04500       ast_mutex_lock(&sla.lock);
04501       sla.stop = 1;
04502       ast_cond_signal(&sla.cond);
04503       ast_mutex_unlock(&sla.lock);
04504       pthread_join(sla.thread, NULL);
04505    }
04506 
04507    /* Drop any created contexts from the dialplan */
04508    ast_context_destroy(NULL, sla_registrar);
04509 
04510    ast_mutex_destroy(&sla.lock);
04511    ast_cond_destroy(&sla.cond);
04512 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 3351 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

03352 {
03353    sla_queue_event(SLA_EVENT_DIAL_STATE);
03354 }

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

References AST_RWLIST_TRAVERSE.

Referenced by sla_station_exec().

03142 {
03143    struct sla_station *station = NULL;
03144 
03145    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03146       if (!strcasecmp(station->name, name))
03147          break;
03148    }
03149 
03150    return station;
03151 }

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

References AST_RWLIST_TRAVERSE.

Referenced by sla_trunk_exec().

03127 {
03128    struct sla_trunk *trunk = NULL;
03129 
03130    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03131       if (!strcasecmp(trunk->name, name))
03132          break;
03133    }
03134 
03135    return trunk;
03136 }

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

Definition at line 3606 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_check_station_delay().

03608 {
03609    struct sla_trunk_ref *trunk_ref = NULL;
03610 
03611    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03612       if (trunk_ref->trunk == trunk)
03613          break;
03614    }
03615 
03616    return trunk_ref;
03617 }

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

03183 {
03184    struct sla_trunk_ref *trunk_ref = NULL;
03185 
03186    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03187       if (strcasecmp(trunk_ref->trunk->name, name))
03188          continue;
03189 
03190       if ( (trunk_ref->trunk->barge_disabled 
03191          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
03192          (trunk_ref->trunk->hold_stations 
03193          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
03194          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
03195          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
03196       {
03197          trunk_ref = NULL;
03198       }
03199 
03200       break;
03201    }
03202 
03203    return trunk_ref;
03204 }

static void sla_handle_dial_state_event ( void   )  [static]

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

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

static void sla_handle_hold_event ( struct sla_event event  )  [static]

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

03737 {
03738    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
03739    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
03740    ast_device_state_changed("SLA:%s_%s", 
03741       event->station->name, event->trunk_ref->trunk->name);
03742    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
03743       INACTIVE_TRUNK_REFS, event->trunk_ref);
03744 
03745    if (event->trunk_ref->trunk->active_stations == 1) {
03746       /* The station putting it on hold is the only one on the call, so start
03747        * Music on hold to the trunk. */
03748       event->trunk_ref->trunk->on_hold = 1;
03749       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
03750    }
03751 
03752    ast_softhangup(event->trunk_ref->chan, AST_CAUSE_NORMAL);
03753    event->trunk_ref->chan = NULL;
03754 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 3726 of file app_meetme.c.

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

Referenced by sla_thread().

03727 {
03728    ast_mutex_lock(&sla.lock);
03729    sla_ring_stations();
03730    ast_mutex_unlock(&sla.lock);
03731 
03732    /* Find stations that shouldn't be ringing anymore. */
03733    sla_hangup_stations();
03734 }

static void sla_hangup_stations ( void   )  [static]

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

03699 {
03700    struct sla_trunk_ref *trunk_ref;
03701    struct sla_ringing_station *ringing_station;
03702 
03703    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03704       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03705          struct sla_ringing_trunk *ringing_trunk;
03706          ast_mutex_lock(&sla.lock);
03707          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03708             if (trunk_ref->trunk == ringing_trunk->trunk)
03709                break;
03710          }
03711          ast_mutex_unlock(&sla.lock);
03712          if (ringing_trunk)
03713             break;
03714       }
03715       if (!trunk_ref) {
03716          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03717          ast_dial_join(ringing_station->station->dial);
03718          ast_dial_destroy(ringing_station->station->dial);
03719          ringing_station->station->dial = NULL;
03720          free(ringing_station);
03721       }
03722    }
03723    AST_LIST_TRAVERSE_SAFE_END
03724 }

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

Definition at line 1038 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

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

static int sla_load_config ( void   )  [static]

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

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

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

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

Referenced by sla_thread().

03915 {
03916    unsigned int timeout = UINT_MAX;
03917    struct timeval tv;
03918    unsigned int change_made = 0;
03919 
03920    /* Check for ring timeouts on ringing trunks */
03921    if (sla_calc_trunk_timeouts(&timeout))
03922       change_made = 1;
03923 
03924    /* Check for ring timeouts on ringing stations */
03925    if (sla_calc_station_timeouts(&timeout))
03926       change_made = 1;
03927 
03928    /* Check for station ring delays */
03929    if (sla_calc_station_delays(&timeout))
03930       change_made = 1;
03931 
03932    /* queue reprocessing of ringing trunks */
03933    if (change_made)
03934       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
03935 
03936    /* No timeout */
03937    if (timeout == UINT_MAX)
03938       return 0;
03939 
03940    if (ts) {
03941       tv = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
03942       ts->tv_sec = tv.tv_sec;
03943       ts->tv_nsec = tv.tv_usec * 1000;
03944    }
03945 
03946    return 1;
03947 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

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

01312 {
01313    sla_queue_event_full(type, NULL, NULL, 1);
01314 }

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

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

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

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

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1306 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01307 {
01308    sla_queue_event_full(type, NULL, NULL, 0);
01309 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

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

03302 {
03303    char buf[80];
03304    struct sla_station_ref *station_ref;
03305 
03306    snprintf(buf, sizeof(buf), "SLA_%s|K", ringing_trunk->trunk->name);
03307    admin_exec(NULL, buf);
03308    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03309 
03310    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
03311       free(station_ref);
03312 
03313    free(ringing_trunk);
03314 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 627 of file app_meetme.c.

References volume::desired, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

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

static int unload_module ( void   )  [static]

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

04825 {
04826    int res = 0;
04827    
04828    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
04829    res = ast_manager_unregister("MeetmeMute");
04830    res |= ast_manager_unregister("MeetmeUnmute");
04831    res |= ast_unregister_application(app3);
04832    res |= ast_unregister_application(app2);
04833    res |= ast_unregister_application(app);
04834    res |= ast_unregister_application(slastation_app);
04835    res |= ast_unregister_application(slatrunk_app);
04836 
04837    ast_devstate_prov_del("Meetme");
04838    ast_devstate_prov_del("SLA");
04839 
04840    ast_module_user_hangup_all();
04841    
04842    sla_destroy();
04843 
04844    return res;
04845 }


Variable Documentation

const char* app = "MeetMe" [static]

Definition at line 202 of file app_meetme.c.

const char* app2 = "MeetMeCount" [static]

Definition at line 203 of file app_meetme.c.

const char* app3 = "MeetMeAdmin" [static]

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

Referenced by load_config_meetme().

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1184 of file app_meetme.c.

Referenced by load_module(), and unload_module().

ast_cond_t cond

Definition at line 524 of file app_meetme.c.

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

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

Definition at line 351 of file app_meetme.c.

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

const char* descrip [static]

Definition at line 214 of file app_meetme.c.

const char* descrip2 [static]

Definition at line 262 of file app_meetme.c.

const char* descrip3 [static]

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

ast_mutex_t lock

Definition at line 525 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 1034 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 469 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 1180 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 1111 of file app_meetme.c.

const char* slastation_app = "SLAStation" [static]

Definition at line 205 of file app_meetme.c.

const char* slastation_desc [static]

Definition at line 293 of file app_meetme.c.

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

Definition at line 211 of file app_meetme.c.

const char* slatrunk_app = "SLATrunk" [static]

Definition at line 206 of file app_meetme.c.

const char* slatrunk_desc [static]

Definition at line 306 of file app_meetme.c.

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

Definition at line 212 of file app_meetme.c.

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

Definition at line 208 of file app_meetme.c.

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

Definition at line 209 of file app_meetme.c.

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

Definition at line 210 of file app_meetme.c.

pthread_t thread

The SLA thread ID

Definition at line 523 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 Tue Nov 4 13:20:24 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7