Fri Sep 25 19:28:17 2009

Asterisk developer's documentation


app_meetme.c File Reference

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

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <zaptel/zaptel.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/options.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/astobj.h"
#include "asterisk/devicestate.h"
#include "asterisk/dial.h"
#include "asterisk/causes.h"
#include "enter.h"
#include "leave.h"

Include dependency graph for app_meetme.c:

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

Functions

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

Variables

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


Detailed Description

Meet me conference bridge and Shared Line Appearances.

Author:
Mark Spencer <markster@digium.com>

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

Definition in file app_meetme.c.


Define Documentation

#define AST_FRAME_BITS   32

Definition at line 88 of file app_meetme.c.

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

#define CONF_SIZE   320

Definition at line 107 of file app_meetme.c.

Referenced by conf_run().

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 73 of file app_meetme.c.

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

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 77 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

Definition at line 314 of file app_meetme.c.

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

#define MAX_PIN   80

Definition at line 315 of file app_meetme.c.

Referenced by conf_exec().

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 86 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 85 of file app_meetme.c.

Referenced by conf_run().

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

Referenced by sms_readfile(), and trunkstate2str().

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 74 of file app_meetme.c.

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


Enumeration Type Documentation

anonymous enum

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

Definition at line 79 of file app_meetme.c.

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

anonymous enum

Enumerator:
CONFFLAG_ADMIN  user has admin access on the conference
CONFFLAG_MONITOR  If set the user can only receive audio from the conference
CONFFLAG_POUNDEXIT  If set asterisk will exit conference when '#' is pressed
CONFFLAG_STARMENU  If set asterisk will provide a menu to the user when '*' is pressed
CONFFLAG_TALKER  If set the use can only send audio to the conference
CONFFLAG_QUIET  If set there will be no enter or leave sounds
CONFFLAG_ANNOUNCEUSERCOUNT  If set, when user joins the conference, they will be told the number of users that are already in
CONFFLAG_AGI  Set to run AGI Script in Background
CONFFLAG_MOH  Set to have music on hold when user is alone in conference
CONFFLAG_MARKEDEXIT  If set the MeetMe will return if all marked with this flag left
CONFFLAG_WAITMARKED  If set, the MeetMe will wait until a marked user enters
CONFFLAG_EXIT_CONTEXT  If set, the MeetMe will exit to the specified context
CONFFLAG_MARKEDUSER  If set, the user will be marked
CONFFLAG_INTROUSER  If set, user will be ask record name on entry of conference
CONFFLAG_RECORDCONF  If set, the MeetMe will be recorded
CONFFLAG_MONITORTALKER  If set, the user will be monitored if the user is talking or not
CONFFLAG_DYNAMIC 
CONFFLAG_DYNAMICPIN 
CONFFLAG_EMPTY 
CONFFLAG_EMPTYNOPIN 
CONFFLAG_ALWAYSPROMPT 
CONFFLAG_OPTIMIZETALKER  If set, treats talking users as muted users
CONFFLAG_NOONLYPERSON  If set, won't speak the extra prompt when the first person enters the conference
CONFFLAG_INTROUSERNOREVIEW  If set, user will be asked to record name on entry of conference without review
CONFFLAG_STARTMUTED  If set, the user will be initially self-muted
CONFFLAG_PASS_DTMF  Pass DTMF through the conference
CONFFLAG_SLA_STATION  This is a SLA station. (Only for use by the SLA applications.)
CONFFLAG_SLA_TRUNK  This is a SLA trunk. (Only for use by the SLA applications.)

Definition at line 109 of file app_meetme.c.

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

anonymous enum

Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_ARRAY_SIZE 

Definition at line 166 of file app_meetme.c.

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

Enumerator:
ENTER 
LEAVE 

Definition at line 95 of file app_meetme.c.

00095                     {
00096    ENTER,
00097    LEAVE
00098 };

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

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

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

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

Definition at line 384 of file app_meetme.c.

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

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

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

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 371 of file app_meetme.c.

00371                           {
00372    ALL_TRUNK_REFS,
00373    INACTIVE_TRUNK_REFS,
00374 };

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 90 of file app_meetme.c.

00090                    {
00091    VOL_UP,
00092    VOL_DOWN
00093 };


Function Documentation

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

Definition at line 2996 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

02997 {
02998    return meetmemute(s, m, 1);
02999 }

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

Definition at line 3001 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

03002 {
03003    return meetmemute(s, m, 0);
03004 }

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

The MeetMeadmin application.

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

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

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

static AST_LIST_HEAD_STATIC ( confs  ,
ast_conference   
) [static]

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

static AST_RWLIST_HEAD_STATIC ( sla_trunks  ,
sla_trunk   
) [static]

static AST_RWLIST_HEAD_STATIC ( sla_stations  ,
sla_station   
) [static]

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

Find or create a conference.

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

Definition at line 739 of file app_meetme.c.

References ast_calloc, AST_FORMAT_SLINEAR, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), AST_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().

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

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

Definition at line 574 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

Referenced by conf_play(), and conf_run().

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

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

Definition at line 970 of file app_meetme.c.

References ast_cli_complete(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_strdupa, ast_conference::confno, len, strdup, strsep(), and ast_conf_user::user_no.

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

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

The meetme() application.

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

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

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

Definition at line 1196 of file app_meetme.c.

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

Referenced by conf_run().

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

static int conf_free ( struct ast_conference conf  )  [static]

Definition at line 1227 of file app_meetme.c.

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

Referenced by dispose_conf().

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

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

Definition at line 692 of file app_meetme.c.

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

Referenced by conf_run().

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

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

Definition at line 1268 of file app_meetme.c.

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

Referenced by conf_run().

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

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

Definition at line 1368 of file app_meetme.c.

References 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, 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::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_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_channel::spies, 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().

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

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

The MeetmeCount application.

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

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

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

Definition at line 4286 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station().

04287 {
04288    struct sla_trunk_ref *trunk_ref;
04289 
04290    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
04291       return NULL;
04292 
04293    trunk_ref->trunk = trunk;
04294 
04295    return trunk_ref;
04296 }

static void destroy_station ( struct sla_station station  )  [static]

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

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

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

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

04440 {
04441    struct sla_station_ref *station_ref;
04442 
04443    if (!ast_strlen_zero(trunk->autocontext))
04444       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
04445 
04446    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
04447       free(station_ref);
04448 
04449    ast_string_field_free_memory(trunk);
04450    free(trunk);
04451 }

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

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

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

static int dispose_conf ( struct ast_conference conf  )  [static]

Definition at line 1349 of file app_meetme.c.

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

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

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

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

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

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

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

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

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

Definition at line 2765 of file app_meetme.c.

References AST_LIST_TRAVERSE, and ast_conf_user::user_no.

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

static char* istalking ( int  x  )  [static]

Definition at line 564 of file app_meetme.c.

Referenced by meetme_cmd().

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

static int load_config ( int  reload  )  [static]

Definition at line 4807 of file app_meetme.c.

References load_config_meetme(), and sla_load_config().

04808 {
04809    int res = 0;
04810 
04811    load_config_meetme();
04812    if (!reload)
04813       res = sla_load_config();
04814 
04815    return res;
04816 }

static void load_config_meetme ( void   )  [static]

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

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

static int load_module ( void   )  [static]

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

Definition at line 822 of file app_meetme.c.

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

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

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

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

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

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

Callback for devicestate providers.

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

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

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

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

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

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

Definition at line 3006 of file app_meetme.c.

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

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

static int reload ( void   )  [static]

Definition at line 4866 of file app_meetme.c.

References load_config().

04867 {
04868    return load_config(1);
04869 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 684 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

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

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

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

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

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

Definition at line 613 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

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

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

Definition at line 601 of file app_meetme.c.

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

Referenced by conf_run(), and tweak_talk_volume().

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 4509 of file app_meetme.c.

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

Referenced by sla_build_trunk().

04510 {
04511    char *tech, *tech_data;
04512 
04513    tech_data = ast_strdupa(device);
04514    tech = strsep(&tech_data, "/");
04515 
04516    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
04517       return -1;
04518 
04519    return 0;
04520 }

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

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

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

Check to see if a station is in use.

Definition at line 3590 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

03591 {
03592    struct sla_trunk_ref *trunk_ref;
03593 
03594    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03595       if (trunk_ref->chan)
03596          return 1;
03597    }
03598 
03599    return 0;
03600 }

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

03490 {
03491    struct sla_ringing_station *ringing_station;
03492 
03493    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
03494       if (station == ringing_station->station)
03495          return 1;
03496    }
03497 
03498    return 0;
03499 }

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

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

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

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

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

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

References AST_LIST_TRAVERSE.

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

03357 {
03358    struct sla_station_ref *timed_out_station;
03359 
03360    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
03361       if (station == timed_out_station->station)
03362          return 1;
03363    }
03364 
03365    return 0;
03366 }

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

References AST_LIST_TRAVERSE, and SLA_TRUNK_STATE_IDLE.

Referenced by sla_station_exec().

04121 {
04122    struct sla_trunk_ref *trunk_ref = NULL;
04123 
04124    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04125       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
04126          break;
04127    }
04128 
04129    return trunk_ref;
04130 }

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

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

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

Definition at line 3214 of file app_meetme.c.

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

Referenced by sla_ring_station().

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

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

Definition at line 3202 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().

03203 {
03204    struct sla_station_ref *station_ref;
03205 
03206    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
03207       return NULL;
03208 
03209    station_ref->station = station;
03210 
03211    return station_ref;
03212 }

static void sla_destroy ( void   )  [static]

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

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

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 3347 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

03348 {
03349    sla_queue_event(SLA_EVENT_DIAL_STATE);
03350 }

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

References AST_RWLIST_TRAVERSE.

Referenced by sla_station_exec().

03138 {
03139    struct sla_station *station = NULL;
03140 
03141    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03142       if (!strcasecmp(station->name, name))
03143          break;
03144    }
03145 
03146    return station;
03147 }

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

References AST_RWLIST_TRAVERSE.

Referenced by sla_trunk_exec().

03123 {
03124    struct sla_trunk *trunk = NULL;
03125 
03126    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03127       if (!strcasecmp(trunk->name, name))
03128          break;
03129    }
03130 
03131    return trunk;
03132 }

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

Definition at line 3602 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_check_station_delay().

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

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

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

static void sla_handle_dial_state_event ( void   )  [static]

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

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

static void sla_handle_hold_event ( struct sla_event event  )  [static]

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

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

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 3722 of file app_meetme.c.

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

Referenced by sla_thread().

03723 {
03724    ast_mutex_lock(&sla.lock);
03725    sla_ring_stations();
03726    ast_mutex_unlock(&sla.lock);
03727 
03728    /* Find stations that shouldn't be ringing anymore. */
03729    sla_hangup_stations();
03730 }

static void sla_hangup_stations ( void   )  [static]

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

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

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

Definition at line 1036 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

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

static int sla_load_config ( void   )  [static]

Definition at line 4765 of file app_meetme.c.

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

Referenced by load_config().

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

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

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

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

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

Referenced by conf_run().

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

static void sla_queue_event_full ( enum sla_event_type  type,
struct sla_trunk_ref trunk_ref,
struct sla_station station,
int  lock 
) [static]

Definition at line 1281 of file app_meetme.c.

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

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

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

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1304 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

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

static int sla_ring_station ( struct sla_ringing_trunk ringing_trunk,
struct sla_station station 
) [static]

Ring a station.

Note:
Assumes sla.lock is locked

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

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

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

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

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

Definition at line 1113 of file app_meetme.c.

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

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

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

Definition at line 1053 of file app_meetme.c.

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

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

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

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

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

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

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

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

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

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

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

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

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

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

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

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

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

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

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

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

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

Definition at line 1095 of file app_meetme.c.

References S, SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, and SLA_TRUNK_STATE_UP.

Referenced by sla_show_stations().

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

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

Definition at line 672 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

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

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

Definition at line 660 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

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

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

Definition at line 625 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

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

static int unload_module ( void   )  [static]

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

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


Variable Documentation

const char* app = "MeetMe" [static]

Definition at line 200 of file app_meetme.c.

const char* app2 = "MeetMeCount" [static]

Definition at line 201 of file app_meetme.c.

const char* app3 = "MeetMeAdmin" [static]

Definition at line 202 of file app_meetme.c.

int audio_buffers [static]

The number of audio buffers to be allocated on pseudo channels when in a conference

Definition at line 538 of file app_meetme.c.

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1182 of file app_meetme.c.

Definition at line 522 of file app_meetme.c.

Referenced by _macro_exec(), and ast_safe_sleep_conditional().

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

Definition at line 349 of file app_meetme.c.

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

const char* descrip [static]

Definition at line 212 of file app_meetme.c.

const char* descrip2 [static]

Definition at line 260 of file app_meetme.c.

const char* descrip3 [static]

Definition at line 268 of file app_meetme.c.

char const gain_map[] [static]

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

Definition at line 546 of file app_meetme.c.

Definition at line 523 of file app_meetme.c.

char meetme_usage[] [static]

Initial value:

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

Definition at line 1032 of file app_meetme.c.

struct { ... } sla [static]

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

const char sla_show_trunks_usage[] [static]

Initial value:

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

Definition at line 1109 of file app_meetme.c.

const char* slastation_app = "SLAStation" [static]

Definition at line 203 of file app_meetme.c.

const char* slastation_desc [static]

Definition at line 291 of file app_meetme.c.

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

Definition at line 209 of file app_meetme.c.

const char* slatrunk_app = "SLATrunk" [static]

Definition at line 204 of file app_meetme.c.

const char* slatrunk_desc [static]

Definition at line 304 of file app_meetme.c.

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

Definition at line 210 of file app_meetme.c.

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

Definition at line 206 of file app_meetme.c.

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

Definition at line 207 of file app_meetme.c.

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

Definition at line 208 of file app_meetme.c.

pthread_t thread


Generated on Fri Sep 25 19:28:18 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.5