Mon May 14 04:43:56 2007

Asterisk developer's documentation


app_meetme.c File Reference

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

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

Include dependency graph for app_meetme.c:

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

Functions

static int action_meetmemute (struct mansession *s, const struct message *m)
static int action_meetmeunmute (struct mansession *s, const struct message *m)
static int admin_exec (struct ast_channel *chan, void *data)
 The MeetMeadmin application.
 AST_APP_OPTIONS (meetme_opts, BEGIN_OPTIONS AST_APP_OPTION('A', CONFFLAG_MARKEDUSER), AST_APP_OPTION('a', CONFFLAG_ADMIN), AST_APP_OPTION('b', CONFFLAG_AGI), AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT), AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN), AST_APP_OPTION('d', CONFFLAG_DYNAMIC), AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN), AST_APP_OPTION('e', CONFFLAG_EMPTY), AST_APP_OPTION('F', CONFFLAG_PASS_DTMF), AST_APP_OPTION('i', CONFFLAG_INTROUSER), AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW), AST_APP_OPTION('M', CONFFLAG_MOH), AST_APP_OPTION('m', CONFFLAG_STARTMUTED), AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER), AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT), AST_APP_OPTION('p', CONFFLAG_POUNDEXIT), AST_APP_OPTION('q', CONFFLAG_QUIET), AST_APP_OPTION('r', CONFFLAG_RECORDCONF), AST_APP_OPTION('s', CONFFLAG_STARMENU), AST_APP_OPTION('T', CONFFLAG_MONITORTALKER), AST_APP_OPTION('l', CONFFLAG_MONITOR), AST_APP_OPTION('t', CONFFLAG_TALKER), AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED), AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT), AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT), AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON), END_OPTIONS)
static AST_LIST_HEAD_STATIC (confs, ast_conference)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"MeetMe conference bridge",.load=load_module,.unload=unload_module,.reload=reload,)
static AST_RWLIST_HEAD_STATIC (sla_trunks, sla_trunk)
static AST_RWLIST_HEAD_STATIC (sla_stations, sla_station)
static struct ast_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 const char const gain_map []
static char meetme_usage []
struct {
   ast_cond_t   cond
   ast_mutex_t   lock
   pthread_t   thread
sla
 A structure for data used by the sla thread.
static const char sla_registrar [] = "SLA"
static const char sla_show_stations_usage []
static const char sla_show_trunks_usage []
static const char * slastation_app = "SLAStation"
static const char * slastation_desc
static const char * slastation_synopsis = "Shared Line Appearance Station"
static const char * slatrunk_app = "SLATrunk"
static const char * slatrunk_desc
static const char * slatrunk_synopsis = "Shared Line Appearance Trunk"
static const char * synopsis = "MeetMe conference bridge"
static const char * synopsis2 = "MeetMe participant count"
static const char * synopsis3 = "MeetMe conference Administration"


Detailed Description

Meet me conference bridge and Shared Line Appearances.

Author:
Mark Spencer <markster@digium.com>

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

Definition in file app_meetme.c.


Define Documentation

#define AST_FRAME_BITS   32

Definition at line 88 of file app_meetme.c.

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

#define CONF_SIZE   320

Definition at line 107 of file app_meetme.c.

Referenced by conf_run().

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 73 of file app_meetme.c.

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

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 77 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

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

Referenced by conf_exec().

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 86 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 85 of file app_meetme.c.

Referenced by conf_run().

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

Referenced by sms_readfile(), and trunkstate2str().

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 74 of file app_meetme.c.

Referenced by sla_load_config().


Enumeration Type Documentation

anonymous enum

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

Definition at line 79 of file app_meetme.c.

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

anonymous enum

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

Definition at line 109 of file app_meetme.c.

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

anonymous enum

Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_ARRAY_SIZE 

Definition at line 166 of file app_meetme.c.

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

enum entrance_sound

Enumerator:
ENTER 
LEAVE 

Definition at line 95 of file app_meetme.c.

00095                     {
00096    ENTER,
00097    LEAVE
00098 };

enum recording_state

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 100 of file app_meetme.c.

enum sla_event_type

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

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

Definition at line 462 of file app_meetme.c.

00462                     {
00463    /*! A station has put the call on hold */
00464    SLA_EVENT_HOLD,
00465    /*! The state of a dial has changed */
00466    SLA_EVENT_DIAL_STATE,
00467    /*! The state of a ringing trunk has changed */
00468    SLA_EVENT_RINGING_TRUNK,
00469 };

enum sla_hold_access

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

Definition at line 376 of file app_meetme.c.

00376                      {
00377    /*! This means that any station can put it on hold, and any station
00378     * can retrieve the call from hold. */
00379    SLA_HOLD_OPEN,
00380    /*! This means that only the station that put the call on hold may
00381     * retrieve it from hold. */
00382    SLA_HOLD_PRIVATE,
00383 };

enum sla_station_hangup

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 495 of file app_meetme.c.

enum sla_trunk_state

Enumerator:
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 368 of file app_meetme.c.

enum sla_which_trunk_refs

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 363 of file app_meetme.c.

00363                           {
00364    ALL_TRUNK_REFS,
00365    INACTIVE_TRUNK_REFS,
00366 };

enum volume_action

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 90 of file app_meetme.c.

00090                    {
00091    VOL_UP,
00092    VOL_DOWN
00093 };


Function Documentation

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

Definition at line 2947 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

02948 {
02949    return meetmemute(s, m, 1);
02950 }

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

Definition at line 2952 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

02953 {
02954    return meetmemute(s, m, 0);
02955 }

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

The MeetMeadmin application.

Definition at line 2733 of file app_meetme.c.

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

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

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

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

static AST_LIST_HEAD_STATIC ( confs  ,
ast_conference   
) [static]

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

static AST_RWLIST_HEAD_STATIC ( sla_trunks  ,
sla_trunk   
) [static]

static AST_RWLIST_HEAD_STATIC ( sla_stations  ,
sla_station   
) [static]

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

Find or create a conference.

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

Definition at line 731 of file app_meetme.c.

References ast_calloc, AST_FORMAT_SLINEAR, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), ast_request(), ast_set_read_format(), ast_set_write_format(), ast_verbose(), conf_map, ast_conference::confno, free, LOG_WARNING, option_verbose, and VERBOSE_PREFIX_3.

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

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

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

Definition at line 566 of file app_meetme.c.

References ast_log(), and LOG_WARNING.

Referenced by conf_play(), and conf_run().

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

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

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

00950 {
00951    static char *cmds[] = {"lock", "unlock", "mute", "unmute", "kick", "list", NULL};
00952 
00953    int len = strlen(word);
00954    int which = 0;
00955    struct ast_conference *cnf = NULL;
00956    struct ast_conf_user *usr = NULL;
00957    char *confno = NULL;
00958    char usrno[50] = "";
00959    char *myline, *ret = NULL;
00960    
00961    if (pos == 1) {      /* Command */
00962       return ast_cli_complete(word, cmds, state);
00963    } else if (pos == 2) {  /* Conference Number */
00964       AST_LIST_LOCK(&confs);
00965       AST_LIST_TRAVERSE(&confs, cnf, list) {
00966          if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
00967             ret = cnf->confno;
00968             break;
00969          }
00970       }
00971       ret = ast_strdup(ret); /* dup before releasing the lock */
00972       AST_LIST_UNLOCK(&confs);
00973       return ret;
00974    } else if (pos == 3) {
00975       /* User Number || Conf Command option*/
00976       if (strstr(line, "mute") || strstr(line, "kick")) {
00977          if (state == 0 && (strstr(line, "kick") || strstr(line,"mute")) && !strncasecmp(word, "all", len))
00978             return strdup("all");
00979          which++;
00980          AST_LIST_LOCK(&confs);
00981 
00982          /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
00983          myline = ast_strdupa(line);
00984          if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
00985             while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
00986                ;
00987          }
00988          
00989          AST_LIST_TRAVERSE(&confs, cnf, list) {
00990             if (!strcmp(confno, cnf->confno))
00991                 break;
00992          }
00993 
00994          if (cnf) {
00995             /* Search for the user */
00996             AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
00997                snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
00998                if (!strncasecmp(word, usrno, len) && ++which > state)
00999                   break;
01000             }
01001          }
01002          AST_LIST_UNLOCK(&confs);
01003          return usr ? strdup(usrno) : NULL;
01004       } else if ( strstr(line, "list") && ( 0 == state ) )
01005          return strdup("concise");
01006    }
01007 
01008    return NULL;
01009 }

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

The meetme() application.

Definition at line 2470 of file app_meetme.c.

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

Referenced by load_module().

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

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

Definition at line 1175 of file app_meetme.c.

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

Referenced by conf_run().

01176 {
01177    int x;
01178 
01179    /* read any frames that may be waiting on the channel
01180       and throw them away
01181    */
01182    if (chan) {
01183       struct ast_frame *f;
01184 
01185       /* when no frames are available, this will wait
01186          for 1 millisecond maximum
01187       */
01188       while (ast_waitfor(chan, 1)) {
01189          f = ast_read(chan);
01190          if (f)
01191             ast_frfree(f);
01192          else /* channel was hung up or something else happened */
01193             break;
01194       }
01195    }
01196 
01197    /* flush any data sitting in the pseudo channel */
01198    x = ZT_FLUSH_ALL;
01199    if (ioctl(fd, ZT_FLUSH, &x))
01200       ast_log(LOG_WARNING, "Error flushing channel\n");
01201 
01202 }

static int conf_free ( struct ast_conference conf  )  [static]

Definition at line 1206 of file app_meetme.c.

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

Referenced by dispose_conf().

01207 {
01208    int x;
01209    
01210    AST_LIST_REMOVE(&confs, conf, list);
01211 
01212    if (conf->recording == MEETME_RECORD_ACTIVE) {
01213       conf->recording = MEETME_RECORD_TERMINATE;
01214       AST_LIST_UNLOCK(&confs);
01215       while (1) {
01216          usleep(1);
01217          AST_LIST_LOCK(&confs);
01218          if (conf->recording == MEETME_RECORD_OFF)
01219             break;
01220          AST_LIST_UNLOCK(&confs);
01221       }
01222    }
01223 
01224    for (x=0;x<AST_FRAME_BITS;x++) {
01225       if (conf->transframe[x])
01226          ast_frfree(conf->transframe[x]);
01227       if (conf->transpath[x])
01228          ast_translator_free_path(conf->transpath[x]);
01229    }
01230    if (conf->origframe)
01231       ast_frfree(conf->origframe);
01232    if (conf->lchan)
01233       ast_hangup(conf->lchan);
01234    if (conf->chan)
01235       ast_hangup(conf->chan);
01236    else
01237       close(conf->fd);
01238    
01239    free(conf);
01240 
01241    return 0;
01242 }

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

Definition at line 684 of file app_meetme.c.

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

Referenced by conf_run().

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

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

Definition at line 1244 of file app_meetme.c.

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

Referenced by conf_run().

01246 {
01247    struct ast_conf_user *user;
01248 
01249    AST_LIST_TRAVERSE(&conf->userlist, user, list) {
01250       if (user == sender)
01251          continue;
01252       if (ast_write(user->chan, f) < 0)
01253          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01254    }
01255 }

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

Definition at line 1344 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, app, ast_calloc, ast_channel_setoption(), ast_config_AST_SPOOL_DIR, AST_CONTROL_HOLD, ast_device_state_changed(), AST_DIGIT_ANY, ast_dsp_new(), ast_dsp_silence(), ast_fileexists(), AST_FORMAT_SLINEAR, ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_frfree(), AST_FRIENDLY_OFFSET, ast_goto_if_exists(), ast_hangup(), ast_indicate(), AST_LIST_EMPTY, AST_LIST_INSERT_TAIL, AST_LIST_LAST, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, ast_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_conf_user::chan, ast_conference::chan, conf_flush(), conf_play(), conf_queue_dtmf(), CONF_SIZE, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_POUNDEXIT, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_SLA_STATION, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, ast_channel::context, ENTER, EVENT_FLAG_CALL, exitcontext, f, ast_conference::fd, ast_channel::fds, ast_frame::frametype, ast_conference::lchan, ast_conference::listenlock, ast_conference::locked, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, manager_event(), ast_conference::markedusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, MEETME_RECORD_OFF, OPT_ARG_WAITMARKED, option_debug, ast_conference::origframe, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), ast_conference::playlock, ast_channel::rawwriteformat, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, s, set_talk_volume(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_channel::tech, timeout, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_conf_user::userflags, ast_conference::users, VERBOSE_PREFIX_4, VOL_UP, and ast_conference::zapconf.

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

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

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

The MeetmeCount application.

Definition at line 2419 of file app_meetme.c.

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

Referenced by load_module().

02420 {
02421    struct ast_module_user *u;
02422    int res = 0;
02423    struct ast_conference *conf;
02424    int count;
02425    char *localdata;
02426    char val[80] = "0"; 
02427    AST_DECLARE_APP_ARGS(args,
02428       AST_APP_ARG(confno);
02429       AST_APP_ARG(varname);
02430    );
02431 
02432    if (ast_strlen_zero(data)) {
02433       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
02434       return -1;
02435    }
02436 
02437    u = ast_module_user_add(chan);
02438    
02439    if (!(localdata = ast_strdupa(data))) {
02440       ast_module_user_remove(u);
02441       return -1;
02442    }
02443 
02444    AST_STANDARD_APP_ARGS(args, localdata);
02445    
02446    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
02447 
02448    if (conf) {
02449       count = conf->users;
02450       dispose_conf(conf);
02451       conf = NULL;
02452    } else
02453       count = 0;
02454 
02455    if (!ast_strlen_zero(args.varname)){
02456       /* have var so load it and exit */
02457       snprintf(val, sizeof(val), "%d",count);
02458       pbx_builtin_setvar_helper(chan, args.varname, val);
02459    } else {
02460       if (chan->_state != AST_STATE_UP)
02461          ast_answer(chan);
02462       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
02463    }
02464    ast_module_user_remove(u);
02465 
02466    return res;
02467 }

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

Definition at line 4213 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station().

04214 {
04215    struct sla_trunk_ref *trunk_ref;
04216 
04217    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
04218       return NULL;
04219 
04220    trunk_ref->trunk = trunk;
04221 
04222    return trunk_ref;
04223 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 4381 of file app_meetme.c.

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

Referenced by sla_destroy().

04382 {
04383    struct sla_trunk_ref *trunk_ref;
04384 
04385    if (!ast_strlen_zero(station->autocontext)) {
04386       AST_RWLIST_RDLOCK(&sla_trunks);
04387       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04388          char exten[AST_MAX_EXTENSION];
04389          char hint[AST_MAX_APP];
04390          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04391          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04392          ast_context_remove_extension(station->autocontext, exten, 
04393             1, sla_registrar);
04394          ast_context_remove_extension(station->autocontext, hint, 
04395             PRIORITY_HINT, sla_registrar);
04396       }
04397       AST_RWLIST_UNLOCK(&sla_trunks);
04398    }
04399 
04400    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
04401       free(trunk_ref);
04402 
04403    ast_string_field_free_all(station);
04404    free(station);
04405 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 4367 of file app_meetme.c.

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

Referenced by sla_destroy().

04368 {
04369    struct sla_station_ref *station_ref;
04370 
04371    if (!ast_strlen_zero(trunk->autocontext))
04372       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
04373 
04374    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
04375       free(station_ref);
04376 
04377    ast_string_field_free_all(trunk);
04378    free(trunk);
04379 }

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

Definition at line 3955 of file app_meetme.c.

References ast_cond_signal(), ast_dial_answered(), ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_run(), ast_dial_state(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdup, ast_strdupa, ast_strlen_zero(), cid_name, cid_num, dial_trunk_args::cond, dial_trunk_args::cond_lock, free, MAX_CONFNUM, sla, strsep(), and dial_trunk_args::trunk_ref.

Referenced by sla_station_exec().

03956 {
03957    struct dial_trunk_args *args = data;
03958    struct ast_dial *dial;
03959    char *tech, *tech_data;
03960    enum ast_dial_result dial_res;
03961    char conf_name[MAX_CONFNUM];
03962    struct ast_conference *conf;
03963    struct ast_flags conf_flags = { 0 };
03964    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
03965    const char *cid_name = NULL, *cid_num = NULL;
03966 
03967    if (!(dial = ast_dial_create())) {
03968       ast_mutex_lock(args->cond_lock);
03969       ast_cond_signal(args->cond);
03970       ast_mutex_unlock(args->cond_lock);
03971       return NULL;
03972    }
03973 
03974    tech_data = ast_strdupa(trunk_ref->trunk->device);
03975    tech = strsep(&tech_data, "/");
03976    if (ast_dial_append(dial, tech, tech_data) == -1) {
03977       ast_mutex_lock(args->cond_lock);
03978       ast_cond_signal(args->cond);
03979       ast_mutex_unlock(args->cond_lock);
03980       ast_dial_destroy(dial);
03981       return NULL;
03982    }
03983 
03984    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
03985       cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
03986       free(trunk_ref->chan->cid.cid_name);
03987       trunk_ref->chan->cid.cid_name = NULL;
03988    }
03989    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
03990       cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
03991       free(trunk_ref->chan->cid.cid_num);
03992       trunk_ref->chan->cid.cid_num = NULL;
03993    }
03994 
03995    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
03996 
03997    if (cid_name)
03998       trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
03999    if (cid_num)
04000       trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
04001 
04002    if (dial_res != AST_DIAL_RESULT_TRYING) {
04003       ast_mutex_lock(args->cond_lock);
04004       ast_cond_signal(args->cond);
04005       ast_mutex_unlock(args->cond_lock);
04006       ast_dial_destroy(dial);
04007       return NULL;
04008    }
04009 
04010    for (;;) {
04011       unsigned int done = 0;
04012       switch ((dial_res = ast_dial_state(dial))) {
04013       case AST_DIAL_RESULT_ANSWERED:
04014          trunk_ref->trunk->chan = ast_dial_answered(dial);
04015       case AST_DIAL_RESULT_HANGUP:
04016       case AST_DIAL_RESULT_INVALID:
04017       case AST_DIAL_RESULT_FAILED:
04018       case AST_DIAL_RESULT_TIMEOUT:
04019       case AST_DIAL_RESULT_UNANSWERED:
04020          done = 1;
04021       case AST_DIAL_RESULT_TRYING:
04022       case AST_DIAL_RESULT_RINGING:
04023       case AST_DIAL_RESULT_PROGRESS:
04024       case AST_DIAL_RESULT_PROCEEDING:
04025          break;
04026       }
04027       if (done)
04028          break;
04029    }
04030 
04031    if (!trunk_ref->trunk->chan) {
04032       ast_mutex_lock(args->cond_lock);
04033       ast_cond_signal(args->cond);
04034       ast_mutex_unlock(args->cond_lock);
04035       ast_dial_join(dial);
04036       ast_dial_destroy(dial);
04037       return NULL;
04038    }
04039 
04040    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04041    ast_set_flag(&conf_flags, 
04042       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
04043       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
04044    conf = build_conf(conf_name, "", "", 1, 1, 1);
04045 
04046    ast_mutex_lock(args->cond_lock);
04047    ast_cond_signal(args->cond);
04048    ast_mutex_unlock(args->cond_lock);
04049 
04050    if (conf) {
04051       conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
04052       dispose_conf(conf);
04053       conf = NULL;
04054    }
04055 
04056    /* If the trunk is going away, it is definitely now IDLE. */
04057    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04058 
04059    trunk_ref->trunk->chan = NULL;
04060    trunk_ref->trunk->on_hold = 0;
04061 
04062    ast_dial_join(dial);
04063    ast_dial_destroy(dial);
04064 
04065    return NULL;
04066 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Definition at line 1325 of file app_meetme.c.

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

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

01326 {
01327    int res = 0;
01328    int confno_int = 0;
01329 
01330    AST_LIST_LOCK(&confs);
01331    if (ast_atomic_dec_and_test(&conf->refcount)) {
01332       /* Take the conference room number out of an inuse state */
01333       if ((sscanf(conf->confno, "%d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01334          conf_map[confno_int] = 0;
01335       conf_free(conf);
01336       res = 1;
01337    }
01338    AST_LIST_UNLOCK(&confs);
01339 
01340    return res;
01341 }

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

Definition at line 2325 of file app_meetme.c.

References AST_APP_ARG, ast_app_getdata(), ast_config_destroy(), ast_config_load(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_variable_browse(), build_conf(), ast_conference::chan, CONFIG_FILE_NAME, ast_conference::confno, LOG_DEBUG, LOG_WARNING, parse(), ast_conference::pin, ast_conference::pinadmin, ast_conference::refcount, S_OR, and var.

Referenced by conf_exec(), and count_exec().

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

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

Definition at line 2268 of file app_meetme.c.

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

Referenced by conf_exec().

02270 {
02271    struct ast_variable *var;
02272    struct ast_conference *cnf;
02273 
02274    /* Check first in the conference list */
02275    AST_LIST_LOCK(&confs);
02276    AST_LIST_TRAVERSE(&confs, cnf, list) {
02277       if (!strcmp(confno, cnf->confno)) 
02278          break;
02279    }
02280    if (cnf) {
02281       cnf->refcount += refcount;
02282    }
02283    AST_LIST_UNLOCK(&confs);
02284 
02285    if (!cnf) {
02286       char *pin = NULL, *pinadmin = NULL; /* For temp use */
02287       
02288       var = ast_load_realtime("meetme", "confno", confno, NULL);
02289 
02290       if (!var)
02291          return NULL;
02292 
02293       while (var) {
02294          if (!strcasecmp(var->name, "pin")) {
02295             pin = ast_strdupa(var->value);
02296          } else if (!strcasecmp(var->name, "adminpin")) {
02297             pinadmin = ast_strdupa(var->value);
02298          }
02299          var = var->next;
02300       }
02301       ast_variables_destroy(var);
02302       
02303       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount);
02304    }
02305 
02306    if (cnf) {
02307       if (confflags && !cnf->chan &&
02308           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
02309           ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
02310          ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
02311          ast_clear_flag(confflags, CONFFLAG_INTROUSER);
02312       }
02313       
02314       if (confflags && !cnf->chan &&
02315           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
02316          ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
02317          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
02318       }
02319    }
02320 
02321    return cnf;
02322 }

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

Definition at line 2716 of file app_meetme.c.

References AST_LIST_TRAVERSE, and ast_conf_user::user_no.

02717 {
02718    struct ast_conf_user *user = NULL;
02719    int cid;
02720    
02721    sscanf(callerident, "%i", &cid);
02722    if (conf && callerident) {
02723       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
02724          if (cid == user->user_no)
02725             return user;
02726       }
02727    }
02728    return NULL;
02729 }

static char* istalking ( int  x  )  [static]

Definition at line 556 of file app_meetme.c.

Referenced by meetme_cmd().

00557 {
00558    if (x > 0)
00559       return "(talking)";
00560    else if (x < 0)
00561       return "(unmonitored)";
00562    else 
00563       return "(not talking)";
00564 }

static int load_config ( int  reload  )  [static]

Definition at line 4732 of file app_meetme.c.

References load_config_meetme(), and sla_load_config().

04733 {
04734    int res = 0;
04735 
04736    load_config_meetme();
04737    if (!reload)
04738       res = sla_load_config();
04739 
04740    return res;
04741 }

static void load_config_meetme ( void   )  [static]

Definition at line 3044 of file app_meetme.c.

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

Referenced by load_config().

03045 {
03046    struct ast_config *cfg;
03047    const char *val;
03048 
03049    audio_buffers = DEFAULT_AUDIO_BUFFERS;
03050 
03051    if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
03052       return;
03053 
03054    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03055       if ((sscanf(val, "%d", &audio_buffers) != 1)) {
03056          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03057          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03058       } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) {
03059          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03060             ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS);
03061          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03062       }
03063       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03064          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03065    }
03066 
03067    ast_config_destroy(cfg);
03068 }

static int load_module ( void   )  [static]

Definition at line 4766 of file app_meetme.c.

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

04767 {
04768    int res = 0;
04769 
04770    res |= load_config(0);
04771 
04772    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
04773    res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 
04774                 action_meetmemute, "Mute a Meetme user");
04775    res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 
04776                 action_meetmeunmute, "Unmute a Meetme user");
04777    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
04778    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
04779    res |= ast_register_application(app, conf_exec, synopsis, descrip);
04780    res |= ast_register_application(slastation_app, sla_station_exec,
04781                slastation_synopsis, slastation_desc);
04782    res |= ast_register_application(slatrunk_app, sla_trunk_exec,
04783                slatrunk_synopsis, slatrunk_desc);
04784 
04785    res |= ast_devstate_prov_add("Meetme", meetmestate);
04786    res |= ast_devstate_prov_add("SLA", sla_state);
04787 
04788    return res;
04789 }

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

Definition at line 806 of file app_meetme.c.

References admin_exec(), ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, ast_cli(), AST_LIST_EMPTY, AST_LIST_TRAVERSE, 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.

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

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

Definition at line 2886 of file app_meetme.c.

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

Referenced by action_meetmemute(), and action_meetmeunmute().

02887 {
02888    struct ast_conference *conf;
02889    struct ast_conf_user *user;
02890    const char *confid = astman_get_header(m, "Meetme");
02891    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
02892    int userno;
02893 
02894    if (ast_strlen_zero(confid)) {
02895       astman_send_error(s, m, "Meetme conference not specified");
02896       return 0;
02897    }
02898 
02899    if (ast_strlen_zero(userid)) {
02900       astman_send_error(s, m, "Meetme user number not specified");
02901       return 0;
02902    }
02903 
02904    userno = strtoul(userid, &userid, 10);
02905 
02906    if (*userid) {
02907       astman_send_error(s, m, "Invalid user number");
02908       return 0;
02909    }
02910 
02911    /* Look in the conference list */
02912    AST_LIST_LOCK(&confs);
02913    AST_LIST_TRAVERSE(&confs, conf, list) {
02914       if (!strcmp(confid, conf->confno))
02915          break;
02916    }
02917 
02918    if (!conf) {
02919       AST_LIST_UNLOCK(&confs);
02920       astman_send_error(s, m, "Meetme conference does not exist");
02921       return 0;
02922    }
02923 
02924    AST_LIST_TRAVERSE(&conf->userlist, user, list)
02925       if (user->user_no == userno)
02926          break;
02927 
02928    if (!user) {
02929       AST_LIST_UNLOCK(&confs);
02930       astman_send_error(s, m, "User number not found");
02931       return 0;
02932    }
02933 
02934    if (mute)
02935       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
02936    else
02937       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);  /* request user unmuting */
02938 
02939    AST_LIST_UNLOCK(&confs);
02940 
02941    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);
02942 
02943    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
02944    return 0;
02945 }

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

Callback for devicestate providers.

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

03023 {
03024    struct ast_conference *conf;
03025 
03026    /* Find conference */
03027    AST_LIST_LOCK(&confs);
03028    AST_LIST_TRAVERSE(&confs, conf, list) {
03029       if (!strcmp(data, conf->confno))
03030          break;
03031    }
03032    AST_LIST_UNLOCK(&confs);
03033    if (!conf)
03034       return AST_DEVICE_INVALID;
03035 
03036 
03037    /* SKREP to fill */
03038    if (!conf->users)
03039       return AST_DEVICE_NOT_INUSE;
03040 
03041    return AST_DEVICE_INUSE;
03042 }

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

Definition at line 4225 of file app_meetme.c.

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

Referenced by sla_trunk_exec().

04226 {
04227    struct sla_ringing_trunk *ringing_trunk;
04228 
04229    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
04230       return NULL;
04231    
04232    ringing_trunk->trunk = trunk;
04233    ringing_trunk->ring_begin = ast_tvnow();
04234 
04235    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
04236 
04237    ast_mutex_lock(&sla.lock);
04238    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
04239    ast_mutex_unlock(&sla.lock);
04240 
04241    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04242 
04243    return ringing_trunk;
04244 }

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

Definition at line 2957 of file app_meetme.c.

References AST_FRAME_BITS, AST_FRAME_VOICE, 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_conference::lchan, ast_conference::listenlock, MEETME_RECORD_ACTIVE, ast_conference::origframe, ast_conference::recordingfilename, ast_conference::recordingformat, s, and ast_conference::transframe.

02958 {
02959    struct ast_conference *cnf = args;
02960    struct ast_frame *f=NULL;
02961    int flags;
02962    struct ast_filestream *s=NULL;
02963    int res=0;
02964    int x;
02965    const char *oldrecordingfilename = NULL;
02966 
02967    if (!cnf || !cnf->lchan) {
02968       pthread_exit(0);
02969    }
02970 
02971    ast_stopstream(cnf->lchan);
02972    flags = O_CREAT|O_TRUNC|O_WRONLY;
02973 
02974 
02975    cnf->recording = MEETME_RECORD_ACTIVE;
02976    while (ast_waitfor(cnf->lchan, -1) > -1) {
02977       if (cnf->recording == MEETME_RECORD_TERMINATE) {
02978          AST_LIST_LOCK(&confs);
02979          AST_LIST_UNLOCK(&confs);
02980          break;
02981       }
02982       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
02983          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
02984          oldrecordingfilename = cnf->recordingfilename;
02985       }
02986       
02987       f = ast_read(cnf->lchan);
02988       if (!f) {
02989          res = -1;
02990          break;
02991       }
02992       if (f->frametype == AST_FRAME_VOICE) {
02993          ast_mutex_lock(&cnf->listenlock);
02994          for (x=0;x<AST_FRAME_BITS;x++) {
02995             /* Free any translations that have occured */
02996             if (cnf->transframe[x]) {
02997                ast_frfree(cnf->transframe[x]);
02998                cnf->transframe[x] = NULL;
02999             }
03000          }
03001          if (cnf->origframe)
03002             ast_frfree(cnf->origframe);
03003          cnf->origframe = f;
03004          ast_mutex_unlock(&cnf->listenlock);
03005          if (s)
03006             res = ast_writestream(s, f);
03007          if (res) {
03008             ast_frfree(f);
03009             break;
03010          }
03011       }
03012       ast_frfree(f);
03013    }
03014    cnf->recording = MEETME_RECORD_OFF;
03015    if (s)
03016       ast_closestream(s);
03017    
03018    pthread_exit(0);
03019 }

static int reload ( void   )  [static]

Definition at line 4791 of file app_meetme.c.

References load_config().

04792 {
04793    return load_config(1);
04794 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 676 of file app_meetme.c.

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

Referenced by admin_exec().

00677 {
00678    signed char zero_volume = 0;
00679 
00680    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00681    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00682 }

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

Definition at line 3203 of file app_meetme.c.

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

Referenced by sla_handle_dial_state_event().

03204 {
03205    struct sla_station *station;
03206    struct sla_trunk_ref *trunk_ref;
03207    char conf_name[MAX_CONFNUM];
03208    struct ast_flags conf_flags = { 0 };
03209    struct ast_conference *conf;
03210 
03211    {
03212       struct run_station_args *args = data;
03213       station = args->station;
03214       trunk_ref = args->trunk_ref;
03215       ast_mutex_lock(args->cond_lock);
03216       ast_cond_signal(args->cond);
03217       ast_mutex_unlock(args->cond_lock);
03218       /* args is no longer valid here. */
03219    }
03220 
03221    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
03222    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
03223    ast_set_flag(&conf_flags, 
03224       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
03225    ast_answer(trunk_ref->chan);
03226    conf = build_conf(conf_name, "", "", 0, 0, 1);
03227    if (conf) {
03228       conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
03229       dispose_conf(conf);
03230       conf = NULL;
03231    }
03232    trunk_ref->chan = NULL;
03233    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
03234       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
03235       strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
03236       admin_exec(NULL, conf_name);
03237       trunk_ref->trunk->hold_stations = 0;
03238       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03239    }
03240 
03241    ast_dial_join(station->dial);
03242    ast_dial_destroy(station->dial);
03243    station->dial = NULL;
03244 
03245    return NULL;
03246 }

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

Definition at line 605 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

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

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

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

00594 {
00595    char gain_adjust;
00596 
00597    /* attempt to make the adjustment in the channel driver;
00598       if successful, don't adjust in the frame reading routine
00599    */
00600    gain_adjust = gain_map[volume + 5];
00601 
00602    return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00603 }

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

Definition at line 4525 of file app_meetme.c.

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

Referenced by sla_build_station().

04526 {
04527    struct sla_trunk *trunk;
04528    struct sla_trunk_ref *trunk_ref;
04529    struct sla_station_ref *station_ref;
04530    char *trunk_name, *options, *cur;
04531 
04532    options = ast_strdupa(var->value);
04533    trunk_name = strsep(&options, ",");
04534    
04535    AST_RWLIST_RDLOCK(&sla_trunks);
04536    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04537       if (!strcasecmp(trunk->name, trunk_name))
04538          break;
04539    }
04540 
04541    AST_RWLIST_UNLOCK(&sla_trunks);
04542    if (!trunk) {
04543       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
04544       return;
04545    }
04546    if (!(trunk_ref = create_trunk_ref(trunk)))
04547       return;
04548    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
04549 
04550    while ((cur = strsep(&options, ","))) {
04551       char *name, *value = cur;
04552       name = strsep(&value, "=");
04553       if (!strcasecmp(name, "ringtimeout")) {
04554          if (sscanf(value, "%u", &trunk_ref->ring_timeout) != 1) {
04555             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
04556                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04557             trunk_ref->ring_timeout = 0;
04558          }
04559       } else if (!strcasecmp(name, "ringdelay")) {
04560          if (sscanf(value, "%u", &trunk_ref->ring_delay) != 1) {
04561             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
04562                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04563             trunk_ref->ring_delay = 0;
04564          }
04565       } else {
04566          ast_log(LOG_WARNING, "Invalid option '%s' for "
04567             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
04568       }
04569    }
04570 
04571    if (!(station_ref = sla_create_station_ref(station))) {
04572       free(trunk_ref);
04573       return;
04574    }
04575    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
04576    AST_RWLIST_WRLOCK(&sla_trunks);
04577    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
04578    AST_RWLIST_UNLOCK(&sla_trunks);
04579    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
04580 }

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

Definition at line 4582 of file app_meetme.c.

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

Referenced by sla_load_config().

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

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

Definition at line 4447 of file app_meetme.c.

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

Referenced by sla_load_config().

04448 {
04449    struct sla_trunk *trunk;
04450    struct ast_variable *var;
04451    const char *dev;
04452 
04453    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
04454       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
04455       return -1;
04456    }
04457 
04458    if (sla_check_device(dev)) {
04459       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
04460          cat, dev);
04461       return -1;
04462    }
04463 
04464    if (!(trunk = ast_calloc(1, sizeof(*trunk))))
04465       return -1;
04466    if (ast_string_field_init(trunk, 32)) {
04467       free(trunk);
04468       return -1;
04469    }
04470 
04471    ast_string_field_set(trunk, name, cat);
04472    ast_string_field_set(trunk, device, dev);
04473 
04474    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04475       if (!strcasecmp(var->name, "autocontext"))
04476          ast_string_field_set(trunk, autocontext, var->value);
04477       else if (!strcasecmp(var->name, "ringtimeout")) {
04478          if (sscanf(var->value, "%u", &trunk->ring_timeout) != 1) {
04479             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
04480                var->value, trunk->name);
04481             trunk->ring_timeout = 0;
04482          }
04483       } else if (!strcasecmp(var->name, "barge"))
04484          trunk->barge_disabled = ast_false(var->value);
04485       else if (!strcasecmp(var->name, "hold")) {
04486          if (!strcasecmp(var->value, "private"))
04487             trunk->hold_access = SLA_HOLD_PRIVATE;
04488          else if (!strcasecmp(var->value, "open"))
04489             trunk->hold_access = SLA_HOLD_OPEN;
04490          else {
04491             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
04492                var->value, trunk->name);
04493          }
04494       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
04495          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
04496             var->name, var->lineno, SLA_CONFIG_FILE);
04497       }
04498    }
04499 
04500    if (!ast_strlen_zero(trunk->autocontext)) {
04501       struct ast_context *context;
04502       context = ast_context_find_or_create(NULL, trunk->autocontext, sla_registrar);
04503       if (!context) {
04504          ast_log(LOG_ERROR, "Failed to automatically find or create "
04505             "context '%s' for SLA!\n", trunk->autocontext);
04506          destroy_trunk(trunk);
04507          return -1;
04508       }
04509       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
04510          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free, sla_registrar)) {
04511          ast_log(LOG_ERROR, "Failed to automatically create extension "
04512             "for trunk '%s'!\n", trunk->name);
04513          destroy_trunk(trunk);
04514          return -1;
04515       }
04516    }
04517 
04518    AST_RWLIST_WRLOCK(&sla_trunks);
04519    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
04520    AST_RWLIST_UNLOCK(&sla_trunks);
04521 
04522    return 0;
04523 }

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

03820 {
03821    struct sla_station *station;
03822    int res = 0;
03823 
03824    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
03825       struct sla_ringing_trunk *ringing_trunk;
03826       int time_left;
03827 
03828       /* Ignore stations already ringing */
03829       if (sla_check_ringing_station(station))
03830          continue;
03831 
03832       /* Ignore stations already on a call */
03833       if (sla_check_inuse_station(station))
03834          continue;
03835 
03836       /* Ignore stations that don't have one of their trunks ringing */
03837       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
03838          continue;
03839 
03840       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
03841          continue;
03842 
03843       /* If there is no time left, then the station needs to start ringing.
03844        * Return non-zero so that an event will be queued up an event to 
03845        * make that happen. */
03846       if (time_left <= 0) {
03847          res = 1;
03848          continue;
03849       }
03850 
03851       if (time_left < *timeout)
03852          *timeout = time_left;
03853    }
03854 
03855    return res;
03856 }

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

03737 {
03738    struct sla_ringing_trunk *ringing_trunk;
03739    struct sla_ringing_station *ringing_station;
03740    int res = 0;
03741 
03742    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03743       unsigned int ring_timeout = 0;
03744       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
03745       struct sla_trunk_ref *trunk_ref;
03746 
03747       /* If there are any ring timeouts specified for a specific trunk
03748        * on the station, then use the highest per-trunk ring timeout.
03749        * Otherwise, use the ring timeout set for the entire station. */
03750       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03751          struct sla_station_ref *station_ref;
03752          int trunk_time_elapsed, trunk_time_left;
03753 
03754          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03755             if (ringing_trunk->trunk == trunk_ref->trunk)
03756                break;
03757          }
03758          if (!ringing_trunk)
03759             continue;
03760 
03761          /* If there is a trunk that is ringing without a timeout, then the
03762           * only timeout that could matter is a global station ring timeout. */
03763          if (!trunk_ref->ring_timeout)
03764             break;
03765 
03766          /* This trunk on this station is ringing and has a timeout.
03767           * However, make sure this trunk isn't still ringing from a
03768           * previous timeout.  If so, don't consider it. */
03769          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
03770             if (station_ref->station == ringing_station->station)
03771                break;
03772          }
03773          if (station_ref)
03774             continue;
03775 
03776          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03777          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
03778          if (trunk_time_left > final_trunk_time_left)
03779             final_trunk_time_left = trunk_time_left;
03780       }
03781 
03782       /* No timeout was found for ringing trunks, and no timeout for the entire station */
03783       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
03784          continue;
03785 
03786       /* Compute how much time is left for a global station timeout */
03787       if (ringing_station->station->ring_timeout) {
03788          ring_timeout = ringing_station->station->ring_timeout;
03789          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
03790          time_left = (ring_timeout * 1000) - time_elapsed;
03791       }
03792 
03793       /* If the time left based on the per-trunk timeouts is smaller than the
03794        * global station ring timeout, use that. */
03795       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
03796          time_left = final_trunk_time_left;
03797 
03798       /* If there is no time left, the station needs to stop ringing */
03799       if (time_left <= 0) {
03800          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03801          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
03802          res = 1;
03803          continue;
03804       }
03805 
03806       /* There is still some time left for this station to ring, so save that
03807        * timeout if it is the first event scheduled to occur */
03808       if (time_left < *timeout)
03809          *timeout = time_left;
03810    }
03811    AST_LIST_TRAVERSE_SAFE_END
03812 
03813    return res;
03814 }

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

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

Referenced by sla_process_timers().

03708 {
03709    struct sla_ringing_trunk *ringing_trunk;
03710    int res = 0;
03711 
03712    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03713       int time_left, time_elapsed;
03714       if (!ringing_trunk->trunk->ring_timeout)
03715          continue;
03716       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03717       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
03718       if (time_left <= 0) {
03719          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03720          sla_stop_ringing_trunk(ringing_trunk);
03721          res = 1;
03722          continue;
03723       }
03724       if (time_left < *timeout)
03725          *timeout = time_left;
03726    }
03727    AST_LIST_TRAVERSE_SAFE_END
03728 
03729    return res;
03730 }

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

References ast_device_state_changed(), and AST_LIST_TRAVERSE.

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

03180 {
03181    struct sla_station *station;
03182    struct sla_trunk_ref *trunk_ref;
03183 
03184    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
03185       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03186          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
03187             || trunk_ref == exclude)
03188             continue;
03189          trunk_ref->state = state;
03190          ast_device_state_changed("SLA:%s_%s", station->name, trunk->name);
03191          break;
03192       }
03193    }
03194 }

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

Definition at line 4434 of file app_meetme.c.

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

Referenced by sla_build_trunk().

04435 {
04436    char *tech, *tech_data;
04437 
04438    tech_data = ast_strdupa(device);
04439    tech = strsep(&tech_data, "/");
04440 
04441    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
04442       return -1;
04443 
04444    return 0;
04445 }

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

03456 {
03457    struct sla_failed_station *failed_station;
03458    int res = 0;
03459 
03460    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
03461       if (station != failed_station->station)
03462          continue;
03463       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
03464          AST_LIST_REMOVE_CURRENT(&sla.failed_stations, entry);
03465          free(failed_station);
03466          break;
03467       }
03468       res = 1;
03469    }
03470    AST_LIST_TRAVERSE_SAFE_END
03471 
03472    return res;
03473 }

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

Check to see if a station is in use.

Definition at line 3541 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

03542 {
03543    struct sla_trunk_ref *trunk_ref;
03544 
03545    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03546       if (trunk_ref->chan)
03547          return 1;
03548    }
03549 
03550    return 0;
03551 }

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

03441 {
03442    struct sla_ringing_station *ringing_station;
03443 
03444    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
03445       if (station == ringing_station->station)
03446          return 1;
03447    }
03448 
03449    return 0;
03450 }

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

03573 {
03574    struct sla_trunk_ref *trunk_ref;
03575    unsigned int delay = UINT_MAX;
03576    int time_left, time_elapsed;
03577 
03578    if (!ringing_trunk)
03579       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
03580    else
03581       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
03582 
03583    if (!ringing_trunk || !trunk_ref)
03584       return delay;
03585 
03586    /* If this station has a ring delay specific to the highest priority
03587     * ringing trunk, use that.  Otherwise, use the ring delay specified
03588     * globally for the station. */
03589    delay = trunk_ref->ring_delay;
03590    if (!delay)
03591       delay = station->ring_delay;
03592    if (!delay)
03593       return INT_MAX;
03594 
03595    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03596    time_left = (delay * 1000) - time_elapsed;
03597 
03598    return time_left;
03599 }

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

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

03102 {
03103    struct sla_station_ref *station_ref;
03104    struct sla_trunk_ref *trunk_ref;
03105 
03106    /* For each station that has this call on hold, check for private hold. */
03107    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03108       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03109          if (trunk_ref->trunk != trunk || station_ref->station == station)
03110             continue;
03111          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03112             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03113             return 1;
03114          return 0;
03115       }
03116    }
03117 
03118    return 0;
03119 }

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

References AST_LIST_TRAVERSE.

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

03308 {
03309    struct sla_station_ref *timed_out_station;
03310 
03311    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
03312       if (station == timed_out_station->station)
03313          return 1;
03314    }
03315 
03316    return 0;
03317 }

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

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

Definition at line 4070 of file app_meetme.c.

References AST_LIST_TRAVERSE, and SLA_TRUNK_STATE_IDLE.

Referenced by sla_station_exec().

04071 {
04072    struct sla_trunk_ref *trunk_ref = NULL;
04073 
04074    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04075       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
04076          break;
04077    }
04078 
04079    return trunk_ref;
04080 }

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

Choose the highest priority ringing trunk for a station.

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

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

03329 {
03330    struct sla_trunk_ref *s_trunk_ref;
03331    struct sla_ringing_trunk *ringing_trunk = NULL;
03332 
03333    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
03334       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03335          /* Make sure this is the trunk we're looking for */
03336          if (s_trunk_ref->trunk != ringing_trunk->trunk)
03337             continue;
03338 
03339          /* This trunk on the station is ringing.  But, make sure this station
03340           * didn't already time out while this trunk was ringing. */
03341          if (sla_check_timed_out_station(ringing_trunk, station))
03342             continue;
03343 
03344          if (remove)
03345             AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03346 
03347          if (trunk_ref)
03348             *trunk_ref = s_trunk_ref;
03349 
03350          break;
03351       }
03352       AST_LIST_TRAVERSE_SAFE_END
03353    
03354       if (ringing_trunk)
03355          break;
03356    }
03357 
03358    return ringing_trunk;
03359 }

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

Definition at line 3165 of file app_meetme.c.

References ast_calloc, and sla_ringing_station::station.

Referenced by sla_ring_station().

03166 {
03167    struct sla_ringing_station *ringing_station;
03168 
03169    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
03170       return NULL;
03171 
03172    ringing_station->station = station;
03173    ringing_station->ring_begin = ast_tvnow();
03174 
03175    return ringing_station;
03176 }

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

Definition at line 3153 of file app_meetme.c.

References ast_calloc.

Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().

03154 {
03155    struct sla_station_ref *station_ref;
03156 
03157    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
03158       return NULL;
03159 
03160    station_ref->station = station;
03161 
03162    return station_ref;
03163 }

static void sla_destroy ( void   )  [static]

Definition at line 4407 of file app_meetme.c.

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

Referenced by unload_module().

04408 {
04409    struct sla_trunk *trunk;
04410    struct sla_station *station;
04411 
04412    AST_RWLIST_WRLOCK(&sla_trunks);
04413    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
04414       destroy_trunk(trunk);
04415    AST_RWLIST_UNLOCK(&sla_trunks);
04416 
04417    AST_RWLIST_WRLOCK(&sla_stations);
04418    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
04419       destroy_station(station);
04420    AST_RWLIST_UNLOCK(&sla_stations);
04421 
04422    if (sla.thread != AST_PTHREADT_NULL) {
04423       ast_mutex_lock(&sla.lock);
04424       sla.stop = 1;
04425       ast_cond_signal(&sla.cond);
04426       ast_mutex_unlock(&sla.lock);
04427       pthread_join(sla.thread, NULL);
04428    }
04429 
04430    ast_mutex_destroy(&sla.lock);
04431    ast_cond_destroy(&sla.cond);
04432 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 3298 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

03299 {
03300    sla_queue_event(SLA_EVENT_DIAL_STATE);
03301 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 3088 of file app_meetme.c.

References AST_RWLIST_TRAVERSE.

Referenced by sla_station_exec().

03089 {
03090    struct sla_station *station = NULL;
03091 
03092    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03093       if (!strcasecmp(station->name, name))
03094          break;
03095    }
03096 
03097    return station;
03098 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 3073 of file app_meetme.c.

References AST_RWLIST_TRAVERSE.

Referenced by sla_trunk_exec().

03074 {
03075    struct sla_trunk *trunk = NULL;
03076 
03077    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03078       if (!strcasecmp(trunk->name, name))
03079          break;
03080    }
03081 
03082    return trunk;
03083 }

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

Definition at line 3553 of file app_meetme.c.

References AST_LIST_TRAVERSE.

Referenced by sla_check_station_delay().

03555 {
03556    struct sla_trunk_ref *trunk_ref = NULL;
03557 
03558    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03559       if (trunk_ref->trunk == trunk)
03560          break;
03561    }
03562 
03563    return trunk_ref;
03564 }

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

Find a trunk reference on a station by name.

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

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

03130 {
03131    struct sla_trunk_ref *trunk_ref = NULL;
03132 
03133    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03134       if (strcasecmp(trunk_ref->trunk->name, name))
03135          continue;
03136 
03137       if ( (trunk_ref->trunk->barge_disabled 
03138          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
03139          (trunk_ref->trunk->hold_stations 
03140          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
03141          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
03142          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
03143       {
03144          trunk_ref = NULL;
03145       }
03146 
03147       break;
03148    }
03149 
03150    return trunk_ref;
03151 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 3361 of file app_meetme.c.

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

Referenced by sla_thread().

03362 {
03363    struct sla_ringing_station *ringing_station;
03364 
03365    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03366       struct sla_trunk_ref *s_trunk_ref = NULL;
03367       struct sla_ringing_trunk *ringing_trunk = NULL;
03368       struct run_station_args args;
03369       enum ast_dial_result dial_res;
03370       pthread_attr_t attr;
03371       pthread_t dont_care;
03372       ast_mutex_t cond_lock;
03373       ast_cond_t cond;
03374 
03375       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
03376       case AST_DIAL_RESULT_HANGUP:
03377       case AST_DIAL_RESULT_INVALID:
03378       case AST_DIAL_RESULT_FAILED:
03379       case AST_DIAL_RESULT_TIMEOUT:
03380       case AST_DIAL_RESULT_UNANSWERED:
03381          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03382          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
03383          break;
03384       case AST_DIAL_RESULT_ANSWERED:
03385          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03386          /* Find the appropriate trunk to answer. */
03387          ast_mutex_lock(&sla.lock);
03388          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
03389          ast_mutex_unlock(&sla.lock);
03390          if (!ringing_trunk) {
03391             ast_log(LOG_DEBUG, "Found no ringing trunk for station '%s' to answer!\n",
03392                ringing_station->station->name);
03393             break;
03394          }
03395          /* Track the channel that answered this trunk */
03396          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
03397          /* Actually answer the trunk */
03398          ast_answer(ringing_trunk->trunk->chan);
03399          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
03400          /* Now, start a thread that will connect this station to the trunk.  The rest of
03401           * the code here sets up the thread and ensures that it is able to save the arguments
03402           * before they are no longer valid since they are allocated on the stack. */
03403          args.trunk_ref = s_trunk_ref;
03404          args.station = ringing_station->station;
03405          args.cond = &cond;
03406          args.cond_lock = &cond_lock;
03407          free(ringing_trunk);
03408          free(ringing_station);
03409          ast_mutex_init(&cond_lock);
03410          ast_cond_init(&cond, NULL);
03411          pthread_attr_init(&attr);
03412          pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
03413          ast_mutex_lock(&cond_lock);
03414          ast_pthread_create_background(&dont_care, &attr, run_station, &args);
03415          ast_cond_wait(&cond, &cond_lock);
03416          ast_mutex_unlock(&cond_lock);
03417          ast_mutex_destroy(&cond_lock);
03418          ast_cond_destroy(&cond);
03419          pthread_attr_destroy(&attr);
03420          break;
03421       case AST_DIAL_RESULT_TRYING:
03422       case AST_DIAL_RESULT_RINGING:
03423       case AST_DIAL_RESULT_PROGRESS:
03424       case AST_DIAL_RESULT_PROCEEDING:
03425          break;
03426       }
03427       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
03428          /* Queue up reprocessing ringing trunks, and then ringing stations again */
03429          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
03430          sla_queue_event(SLA_EVENT_DIAL_STATE);
03431          break;
03432       }
03433    }
03434    AST_LIST_TRAVERSE_SAFE_END
03435 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 3683 of file app_meetme.c.

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

Referenced by sla_thread().

03684 {
03685    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
03686    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
03687    ast_device_state_changed("SLA:%s_%s", 
03688       event->station->name, event->trunk_ref->trunk->name);
03689    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
03690       INACTIVE_TRUNK_REFS, event->trunk_ref);
03691 
03692    if (event->trunk_ref->trunk->active_stations == 1) {
03693       /* The station putting it on hold is the only one on the call, so start
03694        * Music on hold to the trunk. */
03695       event->trunk_ref->trunk->on_hold = 1;
03696       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
03697    }
03698 
03699    ast_softhangup(event->trunk_ref->chan, AST_CAUSE_NORMAL);
03700    event->trunk_ref->chan = NULL;
03701 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 3673 of file app_meetme.c.

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

Referenced by sla_thread().

03674 {
03675    ast_mutex_lock(&sla.lock);
03676    sla_ring_stations();
03677    ast_mutex_unlock(&sla.lock);
03678 
03679    /* Find stations that shouldn't be ringing anymore. */
03680    sla_hangup_stations();
03681 }

static void sla_hangup_stations ( void   )  [static]

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

03646 {
03647    struct sla_trunk_ref *trunk_ref;
03648    struct sla_ringing_station *ringing_station;
03649 
03650    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03651       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03652          struct sla_ringing_trunk *ringing_trunk;
03653          ast_mutex_lock(&sla.lock);
03654          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03655             if (trunk_ref->trunk == ringing_trunk->trunk)
03656                break;
03657          }
03658          ast_mutex_unlock(&sla.lock);
03659          if (ringing_trunk)
03660             break;
03661       }
03662       if (!trunk_ref) {
03663          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03664          ast_dial_join(ringing_station->station->dial);
03665          ast_dial_destroy(ringing_station->station->dial);
03666          ringing_station->station->dial = NULL;
03667          free(ringing_station);
03668       }
03669    }
03670    AST_LIST_TRAVERSE_SAFE_END
03671 }

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

Definition at line 1015 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01016 {
01017    const char *hold = "Unknown";
01018 
01019    switch (hold_access) {
01020    case SLA_HOLD_OPEN:
01021       hold = "Open";
01022       break;
01023    case SLA_HOLD_PRIVATE:
01024       hold = "Private";
01025    default:
01026       break;
01027    }
01028 
01029    return hold;
01030 }

static int sla_load_config ( void   )  [static]

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

04691 {
04692    struct ast_config *cfg;
04693    const char *cat = NULL;
04694    int res = 0;
04695    const char *val;
04696 
04697    ast_mutex_init(&sla.lock);
04698    ast_cond_init(&sla.cond, NULL);
04699 
04700    if (!(cfg = ast_config_load(SLA_CONFIG_FILE)))
04701       return 0; /* Treat no config as normal */
04702 
04703    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
04704       sla.attempt_callerid = ast_true(val);
04705 
04706    while ((cat = ast_category_browse(cfg, cat)) && !res) {
04707       const char *type;
04708       if (!strcasecmp(cat, "general"))
04709          continue;
04710       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
04711          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
04712             SLA_CONFIG_FILE);
04713          continue;
04714       }
04715       if (!strcasecmp(type, "trunk"))
04716          res = sla_build_trunk(cfg, cat);
04717       else if (!strcasecmp(type, "station"))
04718          res = sla_build_station(cfg, cat);
04719       else {
04720          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
04721             SLA_CONFIG_FILE, type);
04722       }
04723    }
04724 
04725    ast_config_destroy(cfg);
04726 
04727    ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
04728 
04729    return res;
04730 }

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

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

Referenced by sla_thread().

03861 {
03862    unsigned int timeout = UINT_MAX;
03863    struct timeval tv;
03864    unsigned int change_made = 0;
03865 
03866    /* Check for ring timeouts on ringing trunks */
03867    if (sla_calc_trunk_timeouts(&timeout))
03868       change_made = 1;
03869 
03870    /* Check for ring timeouts on ringing stations */
03871    if (sla_calc_station_timeouts(&timeout))
03872       change_made = 1;
03873 
03874    /* Check for station ring delays */
03875    if (sla_calc_station_delays(&timeout))
03876       change_made = 1;
03877 
03878    /* queue reprocessing of ringing trunks */
03879    if (change_made)
03880       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
03881 
03882    /* No timeout */
03883    if (timeout == UINT_MAX)
03884       return 0;
03885 
03886    if (ts) {
03887       tv = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
03888       ts->tv_sec = tv.tv_sec;
03889       ts->tv_nsec = tv.tv_usec * 1000;
03890    }
03891 
03892    return 1;
03893 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

Definition at line 1285 of file app_meetme.c.

References sla_queue_event_full().

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

01286 {
01287    sla_queue_event_full(type, NULL, NULL, 1);
01288 }

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

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

Referenced by conf_run().

01293 {
01294    struct sla_station *station;
01295    struct sla_trunk_ref *trunk_ref = NULL;
01296    char *trunk_name;
01297 
01298    trunk_name = ast_strdupa(conf->confno);
01299    strsep(&trunk_name, "_");
01300    if (ast_strlen_zero(trunk_name)) {
01301       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01302       return;
01303    }
01304 
01305    AST_RWLIST_RDLOCK(&sla_stations);
01306    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01307       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01308          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01309             break;
01310       }
01311       if (trunk_ref)
01312          break;
01313    }
01314    AST_RWLIST_UNLOCK(&sla_stations);
01315 
01316    if (!trunk_ref) {
01317       ast_log(LOG_DEBUG, "Trunk not found for event!\n");
01318       return;
01319    }
01320 
01321    sla_queue_event_full(type, trunk_ref, station, 1);
01322 }

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

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

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

01259 {
01260    struct sla_event *event;
01261 
01262    if (!(event = ast_calloc(1, sizeof(*event))))
01263       return;
01264 
01265    event->type = type;
01266    event->trunk_ref = trunk_ref;
01267    event->station = station;
01268 
01269    if (!lock) {
01270       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01271       return;
01272    }
01273 
01274    ast_mutex_lock(&sla.lock);
01275    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01276    ast_cond_signal(&sla.cond);
01277    ast_mutex_unlock(&sla.lock);
01278 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1280 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01281 {
01282    sla_queue_event_full(type, NULL, NULL, 0);
01283 }

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

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

Referenced by sla_ring_stations().

03479 {
03480    char *tech, *tech_data;
03481    struct ast_dial *dial;
03482    struct sla_ringing_station *ringing_station;
03483    const char *cid_name = NULL, *cid_num = NULL;
03484    enum ast_dial_result res;
03485 
03486    if (!(dial = ast_dial_create()))
03487       return -1;
03488 
03489    ast_dial_set_state_callback(dial, sla_dial_state_callback);
03490    tech_data = ast_strdupa(station->device);
03491    tech = strsep(&tech_data, "/");
03492 
03493    if (ast_dial_append(dial, tech, tech_data) == -1) {
03494       ast_dial_destroy(dial);
03495       return -1;
03496    }
03497 
03498    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
03499       cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
03500       free(ringing_trunk->trunk->chan->cid.cid_name);
03501       ringing_trunk->trunk->chan->cid.cid_name = NULL;
03502    }
03503    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
03504       cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
03505       free(ringing_trunk->trunk->chan->cid.cid_num);
03506       ringing_trunk->trunk->chan->cid.cid_num = NULL;
03507    }
03508 
03509    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
03510    
03511    if (cid_name)
03512       ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
03513    if (cid_num)
03514       ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
03515    
03516    if (res != AST_DIAL_RESULT_TRYING) {
03517       struct sla_failed_station *failed_station;
03518       ast_dial_destroy(dial);
03519       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
03520          return -1;
03521       failed_station->station = station;
03522       failed_station->last_try = ast_tvnow();
03523       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
03524       return -1;
03525    }
03526    if (!(ringing_station = sla_create_ringing_station(station))) {
03527       ast_dial_join(dial);
03528       ast_dial_destroy(dial);
03529       return -1;
03530    }
03531 
03532    station->dial = dial;
03533 
03534    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
03535 
03536    return 0;
03537 }

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

03605 {
03606    struct sla_station_ref *station_ref;
03607    struct sla_ringing_trunk *ringing_trunk;
03608 
03609    /* Make sure that every station that uses at least one of the ringing
03610     * trunks, is ringing. */
03611    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03612       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
03613          int time_left;
03614 
03615          /* Is this station already ringing? */
03616          if (sla_check_ringing_station(station_ref->station))
03617             continue;
03618 
03619          /* Is this station already in a call? */
03620          if (sla_check_inuse_station(station_ref->station))
03621             continue;
03622 
03623          /* Did we fail to dial this station earlier?  If so, has it been
03624           * a minute since we tried? */
03625          if (sla_check_failed_station(station_ref->station))
03626             continue;
03627 
03628          /* If this station already timed out while this trunk was ringing,
03629           * do not dial it again for this ringing trunk. */
03630          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
03631             continue;
03632 
03633          /* Check for a ring delay in progress */
03634          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
03635          if (time_left != INT_MAX && time_left > 0)
03636             continue;
03637 
03638          /* It is time to make this station begin to ring.  Do it! */
03639          sla_ring_station(ringing_trunk, station_ref->station);
03640       }
03641    }
03642    /* Now, all of the stations that should be ringing, are ringing. */
03643 }

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

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

01093 {
01094    const struct sla_station *station;
01095 
01096    ast_cli(fd, "\n" 
01097                "=============================================================\n"
01098                "=== Configured SLA Stations =================================\n"
01099                "=============================================================\n"
01100                "===\n");
01101    AST_RWLIST_RDLOCK(&sla_stations);
01102    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01103       struct sla_trunk_ref *trunk_ref;
01104       char ring_timeout[16] = "(none)";
01105       char ring_delay[16] = "(none)";
01106       if (station->ring_timeout) {
01107          snprintf(ring_timeout, sizeof(ring_timeout), 
01108             "%u", station->ring_timeout);
01109       }
01110       if (station->ring_delay) {
01111          snprintf(ring_delay, sizeof(ring_delay), 
01112             "%u", station->ring_delay);
01113       }
01114       ast_cli(fd, "=== ---------------------------------------------------------\n"
01115                   "=== Station Name:    %s\n"
01116                   "=== ==> Device:      %s\n"
01117                   "=== ==> AutoContext: %s\n"
01118                   "=== ==> RingTimeout: %s\n"
01119                   "=== ==> RingDelay:   %s\n"
01120                   "=== ==> HoldAccess:  %s\n"
01121                   "=== ==> Trunks ...\n",
01122                   station->name, station->device,
01123                   S_OR(station->autocontext, "(none)"), 
01124                   ring_timeout, ring_delay,
01125                   sla_hold_str(station->hold_access));
01126       AST_RWLIST_RDLOCK(&sla_trunks);
01127       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01128          if (trunk_ref->ring_timeout) {
01129             snprintf(ring_timeout, sizeof(ring_timeout),
01130                "%u", trunk_ref->ring_timeout);
01131          } else
01132             strcpy(ring_timeout, "(none)");
01133          if (trunk_ref->ring_delay) {
01134             snprintf(ring_delay, sizeof(ring_delay),
01135                "%u", trunk_ref->ring_delay);
01136          } else
01137             strcpy(ring_delay, "(none)");
01138          ast_cli(fd, "===    ==> Trunk Name: %s\n"
01139                      "===       ==> State:       %s\n"
01140                      "===       ==> RingTimeout: %s\n"
01141                      "===       ==> RingDelay:   %s\n",
01142                      trunk_ref->trunk->name,
01143                      trunkstate2str(trunk_ref->state),
01144                      ring_timeout, ring_delay);
01145       }
01146       AST_RWLIST_UNLOCK(&sla_trunks);
01147       ast_cli(fd, "=== ---------------------------------------------------------\n"
01148                   "===\n");
01149    }
01150    AST_RWLIST_UNLOCK(&sla_stations);
01151    ast_cli(fd, "============================================================\n"
01152                "\n");
01153 
01154    return RESULT_SUCCESS;
01155 }

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

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

01033 {
01034    const struct sla_trunk *trunk;
01035 
01036    ast_cli(fd, "\n"
01037                "=============================================================\n"
01038                "=== Configured SLA Trunks ===================================\n"
01039                "=============================================================\n"
01040                "===\n");
01041    AST_RWLIST_RDLOCK(&sla_trunks);
01042    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01043       struct sla_station_ref *station_ref;
01044       char ring_timeout[16] = "(none)";
01045       if (trunk->ring_timeout)
01046          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01047       ast_cli(fd, "=== ---------------------------------------------------------\n"
01048                   "=== Trunk Name:       %s\n"
01049                   "=== ==> Device:       %s\n"
01050                   "=== ==> AutoContext:  %s\n"
01051                   "=== ==> RingTimeout:  %s\n"
01052                   "=== ==> BargeAllowed: %s\n"
01053                   "=== ==> HoldAccess:   %s\n"
01054                   "=== ==> Stations ...\n",
01055                   trunk->name, trunk->device, 
01056                   S_OR(trunk->autocontext, "(none)"), 
01057                   ring_timeout,
01058                   trunk->barge_disabled ? "No" : "Yes",
01059                   sla_hold_str(trunk->hold_access));
01060       AST_RWLIST_RDLOCK(&sla_stations);
01061       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01062          ast_cli(fd, "===    ==> Station name: %s\n", station_ref->station->name);
01063       AST_RWLIST_UNLOCK(&sla_stations);
01064       ast_cli(fd, "=== ---------------------------------------------------------\n"
01065                   "===\n");
01066    }
01067    AST_RWLIST_UNLOCK(&sla_trunks);
01068    ast_cli(fd, "=============================================================\n"
01069                "\n");
01070 
01071    return RESULT_SUCCESS;
01072 }

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

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

04318 {
04319    char *buf, *station_name, *trunk_name;
04320    struct sla_station *station;
04321    struct sla_trunk_ref *trunk_ref;
04322    int res = AST_DEVICE_INVALID;
04323 
04324    trunk_name = buf = ast_strdupa(data);
04325    station_name = strsep(&trunk_name, "_");
04326 
04327    AST_RWLIST_RDLOCK(&sla_stations);
04328    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04329       if (strcasecmp(station_name, station->name))
04330          continue;
04331       AST_RWLIST_RDLOCK(&sla_trunks);
04332       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04333          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
04334             break;
04335       }
04336       if (!trunk_ref) {
04337          AST_RWLIST_UNLOCK(&sla_trunks);
04338          break;
04339       }
04340       switch (trunk_ref->state) {
04341       case SLA_TRUNK_STATE_IDLE:
04342          res = AST_DEVICE_NOT_INUSE;
04343          break;
04344       case SLA_TRUNK_STATE_RINGING:
04345          res = AST_DEVICE_RINGING;
04346          break;
04347       case SLA_TRUNK_STATE_UP:
04348          res = AST_DEVICE_INUSE;
04349          break;
04350       case SLA_TRUNK_STATE_ONHOLD:
04351       case SLA_TRUNK_STATE_ONHOLD_BYME:
04352          res = AST_DEVICE_ONHOLD;
04353          break;
04354       }
04355       AST_RWLIST_UNLOCK(&sla_trunks);
04356    }
04357    AST_RWLIST_UNLOCK(&sla_stations);
04358 
04359    if (res == AST_DEVICE_INVALID) {
04360       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
04361          trunk_name, station_name);
04362    }
04363 
04364    return res;
04365 }

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

Definition at line 4082 of file app_meetme.c.

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

Referenced by load_module().

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

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

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

03265 {
03266    struct sla_ringing_trunk *ringing_trunk;
03267    struct sla_trunk_ref *trunk_ref;
03268    struct sla_station_ref *station_ref;
03269 
03270    ast_dial_join(ringing_station->station->dial);
03271    ast_dial_destroy(ringing_station->station->dial);
03272    ringing_station->station->dial = NULL;
03273 
03274    if (hangup == SLA_STATION_HANGUP_NORMAL)
03275       goto done;
03276 
03277    /* If the station is being hung up because of a timeout, then add it to the
03278     * list of timed out stations on each of the ringing trunks.  This is so
03279     * that when doing further processing to figure out which stations should be
03280     * ringing, which trunk to answer, determining timeouts, etc., we know which
03281     * ringing trunks we should ignore. */
03282    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03283       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03284          if (ringing_trunk->trunk == trunk_ref->trunk)
03285             break;
03286       }
03287       if (!trunk_ref)
03288          continue;
03289       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
03290          continue;
03291       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
03292    }
03293 
03294 done:
03295    free(ringing_station);
03296 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

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

03249 {
03250    char buf[80];
03251    struct sla_station_ref *station_ref;
03252 
03253    snprintf(buf, sizeof(buf), "SLA_%s|K", ringing_trunk->trunk->name);
03254    admin_exec(NULL, buf);
03255    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03256 
03257    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
03258       free(station_ref);
03259 
03260    free(ringing_trunk);
03261 }

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

Definition at line 3895 of file app_meetme.c.

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

Referenced by sla_load_config().

03896 {
03897    struct sla_failed_station *failed_station;
03898    struct sla_ringing_station *ringing_station;
03899 
03900    ast_mutex_lock(&sla.lock);
03901 
03902    while (!sla.stop) {
03903       struct sla_event *event;
03904       struct timespec ts = { 0, };
03905       unsigned int have_timeout = 0;
03906 
03907       if (AST_LIST_EMPTY(&sla.event_q)) {
03908          if ((have_timeout = sla_process_timers(&ts)))
03909             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
03910          else
03911             ast_cond_wait(&sla.cond, &sla.lock);
03912          if (sla.stop)
03913             break;
03914       }
03915 
03916       if (have_timeout)
03917          sla_process_timers(NULL);
03918 
03919       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
03920          ast_mutex_unlock(&sla.lock);
03921          switch (event->type) {
03922          case SLA_EVENT_HOLD:
03923             sla_handle_hold_event(event);
03924             break;
03925          case SLA_EVENT_DIAL_STATE:
03926             sla_handle_dial_state_event();
03927             break;
03928          case SLA_EVENT_RINGING_TRUNK:
03929             sla_handle_ringing_trunk_event();
03930             break;
03931          }
03932          free(event);
03933          ast_mutex_lock(&sla.lock);
03934       }
03935    }
03936 
03937    ast_mutex_unlock(&sla.lock);
03938 
03939    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
03940       free(ringing_station);
03941 
03942    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
03943       free(failed_station);
03944 
03945    return NULL;
03946 }

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

Definition at line 4246 of file app_meetme.c.

References ALL_TRUNK_REFS, AST_CONTROL_RINGING, ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, build_conf(), ast_conference::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, dispose_conf(), ast_flags::flags, free, LOG_ERROR, MAX_CONFNUM, 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().

04247 {
04248    const char *trunk_name = data;
04249    char conf_name[MAX_CONFNUM];
04250    struct ast_conference *conf;
04251    struct ast_flags conf_flags = { 0 };
04252    struct sla_trunk *trunk;
04253    struct sla_ringing_trunk *ringing_trunk;
04254 
04255    AST_RWLIST_RDLOCK(&sla_trunks);
04256    trunk = sla_find_trunk(trunk_name);
04257    AST_RWLIST_UNLOCK(&sla_trunks);
04258    if (!trunk) {
04259       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", trunk_name);
04260       AST_RWLIST_UNLOCK(&sla_trunks);
04261       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04262       return 0;
04263    }
04264    if (trunk->chan) {
04265       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
04266          trunk_name);
04267       AST_RWLIST_UNLOCK(&sla_trunks);
04268       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04269       return 0;
04270    }
04271    trunk->chan = chan;
04272 
04273    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
04274       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04275       return 0;
04276    }
04277 
04278    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_name);
04279    conf = build_conf(conf_name, "", "", 1, 1, 1);
04280    if (!conf) {
04281       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04282       return 0;
04283    }
04284    ast_set_flag(&conf_flags, 
04285       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF);
04286    ast_indicate(chan, AST_CONTROL_RINGING);
04287    conf_run(chan, conf, conf_flags.flags, NULL);
04288    dispose_conf(conf);
04289    conf = NULL;
04290    trunk->chan = NULL;
04291    trunk->on_hold = 0;
04292 
04293    pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
04294 
04295    /* Remove the entry from the list of ringing trunks if it is still there. */
04296    ast_mutex_lock(&sla.lock);
04297    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04298       if (ringing_trunk->trunk == trunk) {
04299          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
04300          break;
04301       }
04302    }
04303    AST_LIST_TRAVERSE_SAFE_END
04304    ast_mutex_unlock(&sla.lock);
04305    if (ringing_trunk) {
04306       sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04307       free(ringing_trunk);
04308       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
04309       /* Queue reprocessing of ringing trunks to make stations stop ringing
04310        * that shouldn't be ringing after this trunk stopped. */
04311       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04312    }
04313 
04314    return 0;
04315 }

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

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

01075 {
01076 #define S(e) case e: return # e;
01077    switch (state) {
01078    S(SLA_TRUNK_STATE_IDLE)
01079    S(SLA_TRUNK_STATE_RINGING)
01080    S(SLA_TRUNK_STATE_UP)
01081    S(SLA_TRUNK_STATE_ONHOLD)
01082    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01083    }
01084    return "Uknown State";
01085 #undef S
01086 }

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

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

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

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

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

00653 {
00654    tweak_volume(&user->talk, action);
00655    /* attempt to make the adjustment in the channel driver;
00656       if successful, don't adjust in the frame reading routine
00657    */
00658    if (!set_talk_volume(user, user->talk.desired))
00659       user->talk.actual = 0;
00660    else
00661       user->talk.actual = user->talk.desired;
00662 }

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

Definition at line 617 of file app_meetme.c.

References volume::desired, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

00618 {
00619    switch (action) {
00620    case VOL_UP:
00621       switch (vol->desired) { 
00622       case 5:
00623          break;
00624       case 0:
00625          vol->desired = 2;
00626          break;
00627       case -2:
00628          vol->desired = 0;
00629          break;
00630       default:
00631          vol->desired++;
00632          break;
00633       }
00634       break;
00635    case VOL_DOWN:
00636       switch (vol->desired) {
00637       case -5:
00638          break;
00639       case 2:
00640          vol->desired = 0;
00641          break;
00642       case 0:
00643          vol->desired = -2;
00644          break;
00645       default:
00646          vol->desired--;
00647          break;
00648       }
00649    }
00650 }

static int unload_module ( void   )  [static]

Definition at line 4743 of file app_meetme.c.

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

04744 {
04745    int res = 0;
04746    
04747    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
04748    res = ast_manager_unregister("MeetmeMute");
04749    res |= ast_manager_unregister("MeetmeUnmute");
04750    res |= ast_unregister_application(app3);
04751    res |= ast_unregister_application(app2);
04752    res |= ast_unregister_application(app);
04753    res |= ast_unregister_application(slastation_app);
04754    res |= ast_unregister_application(slatrunk_app);
04755 
04756    ast_devstate_prov_del("Meetme");
04757    ast_devstate_prov_del("SLA");
04758 
04759    ast_module_user_hangup_all();
04760    
04761    sla_destroy();
04762 
04763    return res;
04764 }


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

Referenced by load_config_meetme().

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1161 of file app_meetme.c.

Referenced by load_module(), and unload_module().

ast_cond_t cond

Definition at line 514 of file app_meetme.c.

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

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

Definition at line 341 of file app_meetme.c.

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

const char* descrip [static]

Definition at line 212 of file app_meetme.c.

const char* descrip2 [static]

Definition at line 261 of file app_meetme.c.

const char* descrip3 [static]

Definition at line 269 of file app_meetme.c.

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

ast_mutex_t lock

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

struct { ... } sla [static]

A structure for data used by the sla thread.

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

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

Definition at line 459 of file app_meetme.c.

Referenced by destroy_station(), and destroy_trunk().

const char sla_show_stations_usage[] [static]

Initial value:

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

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

const char* slastation_app = "SLAStation" [static]

Definition at line 203 of file app_meetme.c.

const char* slastation_desc [static]

Definition at line 292 of file app_meetme.c.

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

Definition at line 209 of file app_meetme.c.

const char* slatrunk_app = "SLATrunk" [static]

Definition at line 204 of file app_meetme.c.

const char* slatrunk_desc [static]

Initial value:

"  SLATrunk(trunk):\n"
"This application should be executed by an SLA trunk on an inbound call.\n"
"The channel calling this application should correspond to the SLA trunk\n"
"with the name \"trunk\" that is being passed as an argument.\n"

Definition at line 301 of file app_meetme.c.

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

Definition at line 210 of file app_meetme.c.

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

Definition at line 206 of file app_meetme.c.

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

Definition at line 207 of file app_meetme.c.

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

Definition at line 208 of file app_meetme.c.

pthread_t thread

The SLA thread ID

Definition at line 513 of file app_meetme.c.

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


Generated on Mon May 14 04:43:58 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1