Sun Jun 12 16:37:49 2011

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"

Include dependency graph for app_meetme.c:

Go to the source code of this file.

Data Structures

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

Defines

#define AST_FRAME_BITS   32
#define CONF_SIZE   320
#define CONFIG_FILE_NAME   "meetme.conf"
#define DEFAULT_AUDIO_BUFFERS   32
#define MAX_CONFNUM   80
#define MAX_PIN   80
#define MEETME_DELAYDETECTENDTALK   1000
#define MEETME_DELAYDETECTTALK   300
#define S(e)   case e: return # e;
#define SLA_CONFIG_FILE   "sla.conf"

Enumerations

enum  { ADMINFLAG_MUTED = (1 << 1), ADMINFLAG_SELFMUTED = (1 << 2), ADMINFLAG_KICKME = (1 << 3) }
enum  {
  CONFFLAG_ADMIN = (1 << 0), CONFFLAG_MONITOR = (1 << 1), CONFFLAG_POUNDEXIT = (1 << 2), CONFFLAG_STARMENU = (1 << 3),
  CONFFLAG_TALKER = (1 << 4), CONFFLAG_QUIET = (1 << 5), CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6), CONFFLAG_AGI = (1 << 7),
  CONFFLAG_MOH = (1 << 8), CONFFLAG_MARKEDEXIT = (1 << 9), CONFFLAG_WAITMARKED = (1 << 10), CONFFLAG_EXIT_CONTEXT = (1 << 11),
  CONFFLAG_MARKEDUSER = (1 << 12), CONFFLAG_INTROUSER = (1 << 13), CONFFLAG_RECORDCONF = (1<< 14), CONFFLAG_MONITORTALKER = (1 << 15),
  CONFFLAG_DYNAMIC = (1 << 16), CONFFLAG_DYNAMICPIN = (1 << 17), CONFFLAG_EMPTY = (1 << 18), CONFFLAG_EMPTYNOPIN = (1 << 19),
  CONFFLAG_ALWAYSPROMPT = (1 << 20), CONFFLAG_OPTIMIZETALKER = (1 << 21), CONFFLAG_NOONLYPERSON = (1 << 22), CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
  CONFFLAG_STARTMUTED = (1 << 24), CONFFLAG_PASS_DTMF = (1 << 25), CONFFLAG_SLA_STATION = (1 << 26), CONFFLAG_SLA_TRUNK = (1 << 27)
}
enum  { OPT_ARG_WAITMARKED = 0, OPT_ARG_ARRAY_SIZE = 1 }
enum  entrance_sound { ENTER, LEAVE }
enum  recording_state { MEETME_RECORD_OFF, MEETME_RECORD_STARTED, MEETME_RECORD_ACTIVE, MEETME_RECORD_TERMINATE }
enum  sla_event_type { SLA_EVENT_HOLD, SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK }
 Event types that can be queued up for the SLA thread. More...
enum  sla_hold_access { SLA_HOLD_OPEN, SLA_HOLD_PRIVATE }
enum  sla_station_hangup { SLA_STATION_HANGUP_NORMAL, SLA_STATION_HANGUP_TIMEOUT }
enum  sla_trunk_state {
  SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, SLA_TRUNK_STATE_ONHOLD,
  SLA_TRUNK_STATE_ONHOLD_BYME
}
enum  sla_which_trunk_refs { ALL_TRUNK_REFS, INACTIVE_TRUNK_REFS }
enum  volume_action { VOL_UP, VOL_DOWN }

Functions

static int action_meetmemute (struct mansession *s, const struct message *m)
static int action_meetmeunmute (struct mansession *s, const struct message *m)
static int admin_exec (struct ast_channel *chan, void *data)
 The MeetMeadmin application.
 AST_APP_OPTIONS (meetme_opts, BEGIN_OPTIONS AST_APP_OPTION('A', CONFFLAG_MARKEDUSER), AST_APP_OPTION('a', CONFFLAG_ADMIN), AST_APP_OPTION('b', CONFFLAG_AGI), AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT), AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN), AST_APP_OPTION('d', CONFFLAG_DYNAMIC), AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN), AST_APP_OPTION('e', CONFFLAG_EMPTY), AST_APP_OPTION('F', CONFFLAG_PASS_DTMF), AST_APP_OPTION('i', CONFFLAG_INTROUSER), AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW), AST_APP_OPTION('M', CONFFLAG_MOH), AST_APP_OPTION('m', CONFFLAG_STARTMUTED), AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER), AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT), AST_APP_OPTION('p', CONFFLAG_POUNDEXIT), AST_APP_OPTION('q', CONFFLAG_QUIET), AST_APP_OPTION('r', CONFFLAG_RECORDCONF), AST_APP_OPTION('s', CONFFLAG_STARMENU), AST_APP_OPTION('T', CONFFLAG_MONITORTALKER), AST_APP_OPTION('l', CONFFLAG_MONITOR), AST_APP_OPTION('t', CONFFLAG_TALKER), AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED), AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT), AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT), AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON), END_OPTIONS)
static AST_LIST_HEAD_STATIC (confs, ast_conference)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"MeetMe conference bridge",.load=load_module,.unload=unload_module,.reload=reload,)
static AST_RWLIST_HEAD_STATIC (sla_trunks, sla_trunk)
static AST_RWLIST_HEAD_STATIC (sla_stations, sla_station)
static struct ast_conferencebuild_conf (char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount)
 Find or create a conference.
static int careful_write (int fd, unsigned char *data, int len, int block)
static char * complete_meetmecmd (const char *line, const char *word, int pos, int state)
static int conf_exec (struct ast_channel *chan, void *data)
 The meetme() application.
static void conf_flush (int fd, struct ast_channel *chan)
static int conf_free (struct ast_conference *conf)
static void conf_play (struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
static void conf_queue_dtmf (const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
static int conf_run (struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
static int count_exec (struct ast_channel *chan, void *data)
 The MeetmeCount application.
static struct sla_trunk_refcreate_trunk_ref (struct sla_trunk *trunk)
static void destroy_station (struct sla_station *station)
static void destroy_trunk (struct sla_trunk *trunk)
static void * dial_trunk (void *data)
static int dispose_conf (struct ast_conference *conf)
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
static struct ast_conferencefind_conf_realtime (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
static struct ast_conf_userfind_user (struct ast_conference *conf, char *callerident)
static char * istalking (int x)
static int load_config (int reload)
static void load_config_meetme (void)
static int load_module (void)
static int meetme_cmd (int fd, int argc, char **argv)
static int meetmemute (struct mansession *s, const struct message *m, int mute)
static int meetmestate (const char *data)
 Callback for devicestate providers.
static struct sla_ringing_trunkqueue_ringing_trunk (struct sla_trunk *trunk)
static void * recordthread (void *args)
static int reload (void)
static void reset_volumes (struct ast_conf_user *user)
static void * run_station (void *data)
static int set_listen_volume (struct ast_conf_user *user, int volume)
static int set_talk_volume (struct ast_conf_user *user, int volume)
static void sla_add_trunk_to_station (struct sla_station *station, struct ast_variable *var)
static int sla_build_station (struct ast_config *cfg, const char *cat)
static int sla_build_trunk (struct ast_config *cfg, const char *cat)
static int sla_calc_station_delays (unsigned int *timeout)
 Calculate the ring delay for a station.
static int sla_calc_station_timeouts (unsigned int *timeout)
 Process station ring timeouts.
static int sla_calc_trunk_timeouts (unsigned int *timeout)
 Process trunk ring timeouts.
static void sla_change_trunk_state (const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
static int sla_check_device (const char *device)
static int sla_check_failed_station (const struct sla_station *station)
 Check to see if this station has failed to be dialed in the past minute.
static int sla_check_inuse_station (const struct sla_station *station)
 Check to see if a station is in use.
static int sla_check_ringing_station (const struct sla_station *station)
 Check to see if this station is already ringing.
static int sla_check_station_delay (struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
 Calculate the ring delay for a given ringing trunk on a station.
static int sla_check_station_hold_access (const struct sla_trunk *trunk, const struct sla_station *station)
static int sla_check_timed_out_station (const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
 Check to see if dialing this station already timed out for this ringing trunk.
static struct sla_trunk_refsla_choose_idle_trunk (const struct sla_station *station)
 For a given station, choose the highest priority idle trunk.
static struct sla_ringing_trunksla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int remove)
 Choose the highest priority ringing trunk for a station.
static struct sla_ringing_stationsla_create_ringing_station (struct sla_station *station)
static struct sla_station_refsla_create_station_ref (struct sla_station *station)
static void sla_destroy (void)
static void sla_dial_state_callback (struct ast_dial *dial)
static struct sla_stationsla_find_station (const char *name)
 Find an SLA station by name.
static struct sla_trunksla_find_trunk (const char *name)
 Find an SLA trunk by name.
static struct sla_trunk_refsla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk)
static struct sla_trunk_refsla_find_trunk_ref_byname (const struct sla_station *station, const char *name)
 Find a trunk reference on a station by name.
static void sla_handle_dial_state_event (void)
static void sla_handle_hold_event (struct sla_event *event)
static void sla_handle_ringing_trunk_event (void)
static void sla_hangup_stations (void)
static const char * sla_hold_str (unsigned int hold_access)
static int sla_load_config (void)
static int sla_process_timers (struct timespec *ts)
 Calculate the time until the next known event.
static void sla_queue_event (enum sla_event_type type)
static void sla_queue_event_conf (enum sla_event_type type, struct ast_channel *chan, struct ast_conference *conf)
 Queue a SLA event from the conference.
static void sla_queue_event_full (enum sla_event_type type, struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
static void sla_queue_event_nolock (enum sla_event_type type)
static int sla_ring_station (struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
 Ring a station.
static void sla_ring_stations (void)
 Ring stations based on current set of ringing trunks.
static int sla_show_stations (int fd, int argc, char **argv)
static int sla_show_trunks (int fd, int argc, char **argv)
static int sla_state (const char *data)
static int sla_station_exec (struct ast_channel *chan, void *data)
static void sla_stop_ringing_station (struct sla_ringing_station *ringing_station, enum sla_station_hangup hangup)
static void sla_stop_ringing_trunk (struct sla_ringing_trunk *ringing_trunk)
static void * sla_thread (void *data)
static int sla_trunk_exec (struct ast_channel *chan, void *data)
static const char * trunkstate2str (enum sla_trunk_state state)
static void tweak_listen_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_talk_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_volume (struct volume *vol, enum volume_action action)
static int unload_module (void)

Variables

static const char * app = "MeetMe"
static const char * app2 = "MeetMeCount"
static const char * app3 = "MeetMeAdmin"
static int audio_buffers
static struct ast_cli_entry cli_meetme []
static unsigned int conf_map [1024] = {0, }
static const char * descrip
static const char * descrip2
static const char * descrip3
static char const gain_map []
static char meetme_usage []
struct {
   ast_cond_t   cond
   ast_mutex_t   lock
   pthread_t   thread
sla
 A structure for data used by the sla thread.
static const char sla_registrar [] = "SLA"
static const char sla_show_stations_usage []
static const char sla_show_trunks_usage []
static const char * slastation_app = "SLAStation"
static const char * slastation_desc
static const char * slastation_synopsis = "Shared Line Appearance Station"
static const char * slatrunk_app = "SLATrunk"
static const char * slatrunk_desc
static const char * slatrunk_synopsis = "Shared Line Appearance Trunk"
static const char * synopsis = "MeetMe conference bridge"
static const char * synopsis2 = "MeetMe participant count"
static const char * synopsis3 = "MeetMe conference Administration"


Detailed Description

Meet me conference bridge and Shared Line Appearances.

Author:
Mark Spencer <markster@digium.com>

(SLA) Russell Bryant <russell@digium.com>

Definition in file app_meetme.c.


Define Documentation

#define AST_FRAME_BITS   32

Definition at line 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_build_station(), sla_build_trunk(), and sla_load_config().


Enumeration Type Documentation

anonymous enum

Enumerator:
ADMINFLAG_MUTED  User is muted
ADMINFLAG_SELFMUTED  User muted self
ADMINFLAG_KICKME  User has been kicked

Definition at line 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 };

Enumerator:
ENTER 
LEAVE 

Definition at line 97 of file app_meetme.c.

00097                     {
00098    ENTER,
00099    LEAVE
00100 };

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 102 of file app_meetme.c.

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

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

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 };

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 };

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 505 of file app_meetme.c.

Enumerator:
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 378 of file app_meetme.c.

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 };

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

References meetmemute().

Referenced by load_module().

03010 {
03011    return meetmemute(s, m, 1);
03012 }

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

Definition at line 3014 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

03015 {
03016    return meetmemute(s, m, 0);
03017 }

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

The MeetMeadmin application.

Definition at line 2795 of file app_meetme.c.

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

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

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

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

static AST_LIST_HEAD_STATIC ( confs  ,
ast_conference   
) [static]

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

static AST_RWLIST_HEAD_STATIC ( sla_trunks  ,
sla_trunk   
) [static]

static AST_RWLIST_HEAD_STATIC ( sla_stations  ,
sla_station   
) [static]

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

Find or create a conference.

Parameters:
confno The conference name/number
pin The regular user pin
pinadmin The admin pin
make Make the conf if it doesn't exist
dynamic Mark the newly created conference as dynamic
refcount How many references to mark on the conference
Returns:
A pointer to the conference struct, or NULL if it wasn't found and make or dynamic were not set.

Definition at line 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(), ast_conference::chan, conf_map, ast_conference::confno, ast_conference::fd, ast_channel::fds, free, ast_conference::isdynamic, ast_conference::listenlock, LOG_WARNING, option_verbose, ast_conference::pin, ast_conference::pinadmin, ast_conference::playlock, ast_conference::recordthread, ast_conference::recordthreadlock, ast_conference::refcount, ast_conference::start, VERBOSE_PREFIX_3, and ast_conference::zapconf.

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

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

References ast_channel::_state, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options(), ast_config_destroy(), ast_config_load(), AST_DECLARE_APP_ARGS, AST_DIGIT_ANY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_module_user_add, ast_module_user_remove, ast_say_digits(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_variable_browse(), ast_waitstream(), conf_map, conf_run(), CONFFLAG_ADMIN, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFIG_FILE_NAME, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), ast_flags::flags, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, ast_variable::name, ast_variable::next, OPT_ARG_ARRAY_SIZE, ast_conference::pin, ast_conference::pinadmin, strsep(), ast_variable::value, and var.

Referenced by load_module().

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

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(), 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, MEETME_RECORD_TERMINATE, 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(), enter, ENTER, ast_conference::fd, leave, 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, 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 volume::actual, ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, ast_calloc, ast_channel_setoption(), ast_check_hangup(), ast_config_AST_SPOOL_DIR, AST_CONTROL_HOLD, ast_device_state_changed(), AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_new(), ast_dsp_silence(), ast_filedelete(), ast_fileexists(), AST_FORMAT_SLINEAR, ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_frfree, AST_FRIENDLY_OFFSET, ast_goto_if_exists(), ast_hangup(), ast_indicate(), AST_LIST_EMPTY, AST_LIST_INSERT_TAIL, AST_LIST_LAST, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, AST_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_conference::chan, ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, conf_flush(), conf_play(), conf_queue_dtmf(), CONF_SIZE, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_POUNDEXIT, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_SLA_STATION, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, ast_channel::context, ast_frame::data, ast_frame::datalen, volume::desired, ENTER, errno, EVENT_FLAG_CALL, exitcontext, f, ast_conference::fd, ast_channel::fds, ast_frame::flags, ast_frame::frametype, free, ast_conf_user::jointime, ast_conference::lchan, LEAVE, ast_conf_user::listen, ast_conference::listenlock, ast_conference::locked, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_channel::macrocontext, manager_event(), ast_conference::markedusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, ast_channel::monitor, ast_conf_user::namerecloc, ast_frame::offset, OPT_ARG_WAITMARKED, option_debug, ast_conference::origframe, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_conference::playlock, ast_channel::rawwriteformat, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, reset_volumes(), s, S_OR, ast_frame::samples, set_talk_volume(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_frame::subclass, ast_conf_user::talk, ast_conf_user::talking, ast_channel::tech, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_conf_user::user_no, ast_conf_user::userflags, ast_conference::users, VERBOSE_PREFIX_4, VOL_DOWN, VOL_UP, ast_conf_user::zapchannel, and ast_conference::zapconf.

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

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

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

The MeetmeCount application.

Definition at line 2481 of file app_meetme.c.

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

Referenced by load_module().

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

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

Definition at line 4299 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station().

04300 {
04301    struct sla_trunk_ref *trunk_ref;
04302 
04303    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
04304       return NULL;
04305 
04306    trunk_ref->trunk = trunk;
04307 
04308    return trunk_ref;
04309 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 4467 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_build_station(), and sla_destroy().

04468 {
04469    struct sla_trunk_ref *trunk_ref;
04470 
04471    if (!ast_strlen_zero(station->autocontext)) {
04472       AST_RWLIST_RDLOCK(&sla_trunks);
04473       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04474          char exten[AST_MAX_EXTENSION];
04475          char hint[AST_MAX_APP];
04476          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04477          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04478          ast_context_remove_extension(station->autocontext, exten, 
04479             1, sla_registrar);
04480          ast_context_remove_extension(station->autocontext, hint, 
04481             PRIORITY_HINT, sla_registrar);
04482       }
04483       AST_RWLIST_UNLOCK(&sla_trunks);
04484    }
04485 
04486    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
04487       free(trunk_ref);
04488 
04489    ast_string_field_free_memory(station);
04490    free(station);
04491 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 4453 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_build_trunk(), and sla_destroy().

04454 {
04455    struct sla_station_ref *station_ref;
04456 
04457    if (!ast_strlen_zero(trunk->autocontext))
04458       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
04459 
04460    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
04461       free(station_ref);
04462 
04463    ast_string_field_free_memory(trunk);
04464    free(trunk);
04465 }

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

Definition at line 4018 of file app_meetme.c.

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

Referenced by sla_station_exec().

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

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(), dial_trunk(), 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, read]

Definition at line 2387 of file app_meetme.c.

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

Referenced by conf_exec(), and count_exec().

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

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

Definition at line 2330 of file app_meetme.c.

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

Referenced by conf_exec().

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

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

Definition at line 2778 of file app_meetme.c.

References AST_LIST_TRAVERSE, and ast_conf_user::user_no.

02779 {
02780    struct ast_conf_user *user = NULL;
02781    int cid;
02782    
02783    sscanf(callerident, "%i", &cid);
02784    if (conf && callerident) {
02785       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
02786          if (cid == user->user_no)
02787             return user;
02788       }
02789    }
02790    return NULL;
02791 }

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

References load_config_meetme(), and sla_load_config().

04823 {
04824    int res = 0;
04825 
04826    load_config_meetme();
04827    if (!reload)
04828       res = sla_load_config();
04829 
04830    return res;
04831 }

static void load_config_meetme ( void   )  [static]

Definition at line 3106 of file app_meetme.c.

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

Referenced by load_config().

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

static int load_module ( void   )  [static]

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

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

Referenced by action_meetmemute(), and action_meetmeunmute().

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

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

Callback for devicestate providers.

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

03085 {
03086    struct ast_conference *conf;
03087 
03088    /* Find conference */
03089    AST_LIST_LOCK(&confs);
03090    AST_LIST_TRAVERSE(&confs, conf, list) {
03091       if (!strcmp(data, conf->confno))
03092          break;
03093    }
03094    AST_LIST_UNLOCK(&confs);
03095    if (!conf)
03096       return AST_DEVICE_INVALID;
03097 
03098 
03099    /* SKREP to fill */
03100    if (!conf->users)
03101       return AST_DEVICE_NOT_INUSE;
03102 
03103    return AST_DEVICE_INUSE;
03104 }

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

Definition at line 4311 of file app_meetme.c.

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

Referenced by sla_trunk_exec().

04312 {
04313    struct sla_ringing_trunk *ringing_trunk;
04314 
04315    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
04316       return NULL;
04317    
04318    ringing_trunk->trunk = trunk;
04319    ringing_trunk->ring_begin = ast_tvnow();
04320 
04321    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
04322 
04323    ast_mutex_lock(&sla.lock);
04324    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
04325    ast_mutex_unlock(&sla.lock);
04326 
04327    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04328 
04329    return ringing_trunk;
04330 }

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

Definition at line 3019 of file app_meetme.c.

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

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

static int reload ( void   )  [static]

Definition at line 4881 of file app_meetme.c.

References load_config().

04882 {
04883    return load_config(1);
04884 }

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(), and conf_run().

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

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

Referenced by sla_handle_dial_state_event().

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

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

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

Referenced by sla_build_station().

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

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

Definition at line 4671 of file app_meetme.c.

References ast_add_extension2(), ast_calloc, ast_context_find_or_create(), ast_free, AST_LIST_TRAVERSE, ast_log(), AST_MAX_APP, AST_MAX_EXTENSION, AST_RWLIST_INSERT_TAIL, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), context, destroy_station(), exten, free, ast_variable::lineno, LOG_ERROR, LOG_WARNING, ast_variable::name, name, ast_variable::next, PRIORITY_HINT, sla_add_trunk_to_station(), SLA_CONFIG_FILE, SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, ast_variable::value, and var.

Referenced by sla_load_config().

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

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

Definition at line 4536 of file app_meetme.c.

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

Referenced by sla_load_config().

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

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

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

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

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

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

03770 {
03771    struct sla_ringing_trunk *ringing_trunk;
03772    int res = 0;
03773 
03774    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03775       int time_left, time_elapsed;
03776       if (!ringing_trunk->trunk->ring_timeout)
03777          continue;
03778       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03779       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
03780       if (time_left <= 0) {
03781          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
03782          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03783          sla_stop_ringing_trunk(ringing_trunk);
03784          res = 1;
03785          continue;
03786       }
03787       if (time_left < *timeout)
03788          *timeout = time_left;
03789    }
03790    AST_LIST_TRAVERSE_SAFE_END
03791 
03792    return res;
03793 }

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

References ast_device_state_changed(), and AST_LIST_TRAVERSE.

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

03242 {
03243    struct sla_station *station;
03244    struct sla_trunk_ref *trunk_ref;
03245 
03246    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
03247       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03248          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
03249             || trunk_ref == exclude)
03250             continue;
03251          trunk_ref->state = state;
03252          ast_device_state_changed("SLA:%s_%s", station->name, trunk->name);
03253          break;
03254       }
03255    }
03256 }

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

Definition at line 4523 of file app_meetme.c.

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

Referenced by sla_build_trunk().

04524 {
04525    char *tech, *tech_data;
04526 
04527    tech_data = ast_strdupa(device);
04528    tech = strsep(&tech_data, "/");
04529 
04530    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
04531       return -1;
04532 
04533    return 0;
04534 }

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

03518 {
03519    struct sla_failed_station *failed_station;
03520    int res = 0;
03521 
03522    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
03523       if (station != failed_station->station)
03524          continue;
03525       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
03526          AST_LIST_REMOVE_CURRENT(&sla.failed_stations, entry);
03527          free(failed_station);
03528          break;
03529       }
03530       res = 1;
03531    }
03532    AST_LIST_TRAVERSE_SAFE_END
03533 
03534    return res;
03535 }

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

Check to see if a station is in use.

Definition at line 3603 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

03604 {
03605    struct sla_trunk_ref *trunk_ref;
03606 
03607    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03608       if (trunk_ref->chan)
03609          return 1;
03610    }
03611 
03612    return 0;
03613 }

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

03503 {
03504    struct sla_ringing_station *ringing_station;
03505 
03506    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
03507       if (station == ringing_station->station)
03508          return 1;
03509    }
03510 
03511    return 0;
03512 }

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

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

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

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

03164 {
03165    struct sla_station_ref *station_ref;
03166    struct sla_trunk_ref *trunk_ref;
03167 
03168    /* For each station that has this call on hold, check for private hold. */
03169    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03170       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03171          if (trunk_ref->trunk != trunk || station_ref->station == station)
03172             continue;
03173          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03174             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03175             return 1;
03176          return 0;
03177       }
03178    }
03179 
03180    return 0;
03181 }

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

References AST_LIST_TRAVERSE.

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

03370 {
03371    struct sla_station_ref *timed_out_station;
03372 
03373    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
03374       if (station == timed_out_station->station)
03375          return 1;
03376    }
03377 
03378    return 0;
03379 }

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

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

Definition at line 4133 of file app_meetme.c.

References AST_LIST_TRAVERSE, and SLA_TRUNK_STATE_IDLE.

Referenced by sla_station_exec().

04134 {
04135    struct sla_trunk_ref *trunk_ref = NULL;
04136 
04137    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04138       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
04139          break;
04140    }
04141 
04142    return trunk_ref;
04143 }

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

Choose the highest priority ringing trunk for a station.

Parameters:
station the station
remove remove the ringing trunk once selected
trunk_ref a place to store the pointer to this stations reference to the selected trunk
Returns:
a pointer to the selected ringing trunk, or NULL if none found
Note:
Assumes that sla.lock is locked

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

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

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

Definition at line 3227 of file app_meetme.c.

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

Referenced by sla_ring_station().

03228 {
03229    struct sla_ringing_station *ringing_station;
03230 
03231    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
03232       return NULL;
03233 
03234    ringing_station->station = station;
03235    ringing_station->ring_begin = ast_tvnow();
03236 
03237    return ringing_station;
03238 }

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

Definition at line 3215 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().

03216 {
03217    struct sla_station_ref *station_ref;
03218 
03219    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
03220       return NULL;
03221 
03222    station_ref->station = station;
03223 
03224    return station_ref;
03225 }

static void sla_destroy ( void   )  [static]

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

04494 {
04495    struct sla_trunk *trunk;
04496    struct sla_station *station;
04497 
04498    AST_RWLIST_WRLOCK(&sla_trunks);
04499    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
04500       destroy_trunk(trunk);
04501    AST_RWLIST_UNLOCK(&sla_trunks);
04502 
04503    AST_RWLIST_WRLOCK(&sla_stations);
04504    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
04505       destroy_station(station);
04506    AST_RWLIST_UNLOCK(&sla_stations);
04507 
04508    if (sla.thread != AST_PTHREADT_NULL) {
04509       ast_mutex_lock(&sla.lock);
04510       sla.stop = 1;
04511       ast_cond_signal(&sla.cond);
04512       ast_mutex_unlock(&sla.lock);
04513       pthread_join(sla.thread, NULL);
04514    }
04515 
04516    /* Drop any created contexts from the dialplan */
04517    ast_context_destroy(NULL, sla_registrar);
04518 
04519    ast_mutex_destroy(&sla.lock);
04520    ast_cond_destroy(&sla.cond);
04521 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 3360 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

03361 {
03362    sla_queue_event(SLA_EVENT_DIAL_STATE);
03363 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 3150 of file app_meetme.c.

References AST_RWLIST_TRAVERSE.

Referenced by sla_station_exec().

03151 {
03152    struct sla_station *station = NULL;
03153 
03154    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03155       if (!strcasecmp(station->name, name))
03156          break;
03157    }
03158 
03159    return station;
03160 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 3135 of file app_meetme.c.

References AST_RWLIST_TRAVERSE.

Referenced by sla_trunk_exec().

03136 {
03137    struct sla_trunk *trunk = NULL;
03138 
03139    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03140       if (!strcasecmp(trunk->name, name))
03141          break;
03142    }
03143 
03144    return trunk;
03145 }

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

Definition at line 3615 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_check_station_delay().

03617 {
03618    struct sla_trunk_ref *trunk_ref = NULL;
03619 
03620    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03621       if (trunk_ref->trunk == trunk)
03622          break;
03623    }
03624 
03625    return trunk_ref;
03626 }

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

Find a trunk reference on a station by name.

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

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

03192 {
03193    struct sla_trunk_ref *trunk_ref = NULL;
03194 
03195    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03196       if (strcasecmp(trunk_ref->trunk->name, name))
03197          continue;
03198 
03199       if ( (trunk_ref->trunk->barge_disabled 
03200          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
03201          (trunk_ref->trunk->hold_stations 
03202          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
03203          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
03204          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
03205       {
03206          trunk_ref = NULL;
03207       }
03208 
03209       break;
03210    }
03211 
03212    return trunk_ref;
03213 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 3423 of file app_meetme.c.

References ALL_TRUNK_REFS, ast_answer(), ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), ast_dial_answered(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_state(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, ast_conference::attr, run_station_args::cond, run_station_args::cond_lock, free, LOG_DEBUG, run_station(), sla, sla_change_trunk_state(), sla_choose_ringing_trunk(), SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_queue_event(), SLA_STATION_HANGUP_NORMAL, sla_stop_ringing_station(), SLA_TRUNK_STATE_UP, run_station_args::station, sla_ringing_station::station, sla_ringing_trunk::trunk, and run_station_args::trunk_ref.

Referenced by sla_thread().

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

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 3745 of file app_meetme.c.

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

Referenced by sla_thread().

03746 {
03747    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
03748    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
03749    ast_device_state_changed("SLA:%s_%s", 
03750       event->station->name, event->trunk_ref->trunk->name);
03751    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
03752       INACTIVE_TRUNK_REFS, event->trunk_ref);
03753 
03754    if (event->trunk_ref->trunk->active_stations == 1) {
03755       /* The station putting it on hold is the only one on the call, so start
03756        * Music on hold to the trunk. */
03757       event->trunk_ref->trunk->on_hold = 1;
03758       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
03759    }
03760 
03761    ast_softhangup(event->trunk_ref->chan, AST_CAUSE_NORMAL);
03762    event->trunk_ref->chan = NULL;
03763 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 3735 of file app_meetme.c.

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

Referenced by sla_thread().

03736 {
03737    ast_mutex_lock(&sla.lock);
03738    sla_ring_stations();
03739    ast_mutex_unlock(&sla.lock);
03740 
03741    /* Find stations that shouldn't be ringing anymore. */
03742    sla_hangup_stations();
03743 }

static void sla_hangup_stations ( void   )  [static]

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

03708 {
03709    struct sla_trunk_ref *trunk_ref;
03710    struct sla_ringing_station *ringing_station;
03711 
03712    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03713       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03714          struct sla_ringing_trunk *ringing_trunk;
03715          ast_mutex_lock(&sla.lock);
03716          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03717             if (trunk_ref->trunk == ringing_trunk->trunk)
03718                break;
03719          }
03720          ast_mutex_unlock(&sla.lock);
03721          if (ringing_trunk)
03722             break;
03723       }
03724       if (!trunk_ref) {
03725          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03726          ast_dial_join(ringing_station->station->dial);
03727          ast_dial_destroy(ringing_station->station->dial);
03728          ringing_station->station->dial = NULL;
03729          free(ringing_station);
03730       }
03731    }
03732    AST_LIST_TRAVERSE_SAFE_END
03733 }

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

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

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

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

static void sla_queue_event ( enum sla_event_type  type  )  [static]

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

Queue a SLA event from the conference.

Definition at line 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::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, and sla.

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

References ast_calloc, ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_TRYING, ast_dial_run(), ast_dial_set_state_callback(), AST_LIST_INSERT_HEAD, ast_strdup, ast_strdupa, ast_strlen_zero(), cid_name, cid_num, free, sla_failed_station::last_try, sla, sla_create_ringing_station(), sla_dial_state_callback(), sla_failed_station::station, strsep(), and sla_ringing_trunk::trunk.

Referenced by sla_ring_stations().

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

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

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

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

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

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

Definition at line 4145 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(), conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, 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, strsep(), sla_ringing_trunk::trunk, and dial_trunk_args::trunk_ref.

Referenced by load_module().

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

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

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

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

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

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

03311 {
03312    char buf[80];
03313    struct sla_station_ref *station_ref;
03314 
03315    snprintf(buf, sizeof(buf), "SLA_%s|K", ringing_trunk->trunk->name);
03316    admin_exec(NULL, buf);
03317    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03318 
03319    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
03320       free(station_ref);
03321 
03322    free(ringing_trunk);
03323 }

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

Definition at line 3958 of file app_meetme.c.

References ast_cond_timedwait(), ast_cond_wait(), AST_LIST_EMPTY, AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), event, free, sla, SLA_EVENT_DIAL_STATE, SLA_EVENT_HOLD, SLA_EVENT_RINGING_TRUNK, sla_handle_dial_state_event(), sla_handle_hold_event(), sla_handle_ringing_trunk_event(), sla_process_timers(), and sla_event::type.

Referenced by sla_load_config().

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

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

Definition at line 4332 of file app_meetme.c.

References ALL_TRUNK_REFS, AST_CONTROL_RINGING, ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, build_conf(), conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, dispose_conf(), ast_flags::flags, free, LOG_ERROR, MAX_CONFNUM, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), queue_ringing_trunk(), sla, sla_change_trunk_state(), SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by load_module().

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

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, VOL_DOWN, 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 4833 of file app_meetme.c.

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

04834 {
04835    int res = 0;
04836    
04837    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
04838    res = ast_manager_unregister("MeetmeMute");
04839    res |= ast_manager_unregister("MeetmeUnmute");
04840    res |= ast_unregister_application(app3);
04841    res |= ast_unregister_application(app2);
04842    res |= ast_unregister_application(app);
04843    res |= ast_unregister_application(slastation_app);
04844    res |= ast_unregister_application(slatrunk_app);
04845 
04846    ast_devstate_prov_del("Meetme");
04847    ast_devstate_prov_del("SLA");
04848 
04849    ast_module_user_hangup_all();
04850    
04851    sla_destroy();
04852 
04853    return res;
04854 }


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.

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1184 of file app_meetme.c.

Definition at line 524 of file app_meetme.c.

Referenced by _macro_exec(), ast_safe_sleep_conditional(), 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.

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]

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

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


Generated on Sun Jun 12 16:37:49 2011 for Asterisk - the Open Source PBX by  doxygen 1.5.6