Wed Mar 3 22:40:47 2010

Asterisk developer's documentation


app_meetme.c File Reference

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

#include "asterisk.h"
#include <dahdi/user.h>
#include "asterisk/lock.h"
#include "asterisk/file.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/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/astobj2.h"
#include "asterisk/devicestate.h"
#include "asterisk/dial.h"
#include "asterisk/causes.h"
#include "asterisk/paths.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  announce_listitem
struct  ast_conf_user
 The MeetMe User object. More...
struct  ast_conference
 The MeetMe Conference object. More...
struct  confs
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_stations
struct  sla_trunk
struct  sla_trunk_ref
struct  sla_trunks
struct  volume

Defines

#define AST_FRAME_BITS   32
#define CONF_SIZE   320
#define CONFIG_FILE_NAME   "meetme.conf"
#define DATE_FORMAT   "%Y-%m-%d %H:%M:%S"
#define DEFAULT_AUDIO_BUFFERS   32
#define MAX_CONFNUM   80
#define MAX_PIN   80
#define MC_DATA_FORMAT   "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
#define MC_HEADER_FORMAT   "%-14s %-14s %-10s %-8s %-8s %-6s\n"
#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), ADMINFLAG_T_REQUEST = (1 << 4) }
enum  {
  CONFFLAG_ADMIN = (1 << 0), CONFFLAG_MONITOR = (1 << 1), CONFFLAG_KEYEXIT = (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),
  CONFFLAG_KICK_CONTINUE = (1 << 28), CONFFLAG_DURATION_STOP = (1 << 29), CONFFLAG_DURATION_LIMIT = (1 << 30), CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31)
}
enum  {
  OPT_ARG_WAITMARKED = 0, OPT_ARG_EXITKEYS = 1, OPT_ARG_DURATION_STOP = 2, OPT_ARG_DURATION_LIMIT = 3,
  OPT_ARG_MOH_CLASS = 4, OPT_ARG_ARRAY_SIZE = 5
}
enum  { SLA_TRUNK_OPT_MOH = (1 << 0) }
enum  { SLA_TRUNK_OPT_ARG_MOH_CLASS = 0, SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1 }
enum  announcetypes { CONF_HASJOIN, CONF_HASLEFT }
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, SLA_EVENT_RELOAD,
  SLA_EVENT_CHECK_RELOAD
}
 

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 void __reg_module (void)
static void __unreg_module (void)
static int acf_meetme_info (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_meetme_info_eval (char *keyword, struct ast_conference *conf)
static int action_meetmelist (struct mansession *s, const struct message *m)
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.
static void * announce_thread (void *data)
static void answer_trunk_chan (struct ast_channel *chan)
static struct ast_conferencebuild_conf (char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan)
 Find or create a conference.
static int can_write (struct ast_channel *chan, int confflags)
static int careful_write (int fd, unsigned char *data, int len, int block)
static int channel_admin_exec (struct ast_channel *chan, void *data)
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 void conf_start_moh (struct ast_channel *chan, const char *musicclass)
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, char *optargs[], int *too_early)
static struct ast_conf_userfind_user (struct ast_conference *conf, char *callerident)
static const char * get_announce_filename (enum announcetypes type)
static char * istalking (int x)
static int load_config (int reload)
static void load_config_meetme (void)
static int load_module (void)
static char * meetme_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int meetmemute (struct mansession *s, const struct message *m, int mute)
static enum ast_device_state 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 void sla_check_reload (void)
 Check if we can do a reload of SLA, and do it if we can.
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 rm)
 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 (int reload)
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 char * sla_show_stations (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * sla_show_trunks (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static enum ast_device_state sla_state (const char *data)
static enum ast_device_state sla_state_to_devstate (enum sla_trunk_state state)
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 struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "MeetMe conference bridge" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, }
static const char * app = "MeetMe"
static const char * app2 = "MeetMeCount"
static const char * app3 = "MeetMeAdmin"
static const char * app4 = "MeetMeChannelAdmin"
static struct ast_module_infoast_module_info = &__mod_info
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 * descrip4
static int earlyalert
static int endalert
static int fuzzystart
static char const gain_map []
static char mandescr_meetmelist []
static struct ast_custom_function meetme_info_acf
static struct ast_app_option meetme_opts [128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
static int rt_log_members
static int rt_schedule
struct {
   unsigned int   attempt_callerid:1
   ast_cond_t   cond
   struct {
      struct sla_event *   first
      struct sla_event *   last
   }   event_q
   struct {
      struct sla_failed_station *   first
      struct sla_failed_station *   last
   }   failed_stations
   ast_mutex_t   lock
   unsigned int   reload:1
   struct {
      struct sla_ringing_station *   first
      struct sla_ringing_station *   last
   }   ringing_stations
   struct {
      struct sla_ringing_trunk *   first
      struct sla_ringing_trunk *   last
   }   ringing_trunks
   unsigned int   stop:1
   pthread_t   thread
sla
 A structure for data used by the sla thread.
static const char sla_registrar [] = "SLA"
static struct ast_app_option sla_trunk_opts [128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, }
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"
static const char * synopsis4 = "MeetMe conference Administration (channel specific)"

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

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

#define CONF_SIZE   320

Definition at line 105 of file app_meetme.c.

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 66 of file app_meetme.c.

#define DATE_FORMAT   "%Y-%m-%d %H:%M:%S"

String format for scheduled conferences

Definition at line 73 of file app_meetme.c.

Referenced by append_date(), build_radius_record(), execute_cb(), find_conf_realtime(), get_date(), manager_log(), pgsql_log(), and sqlite_log().

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 70 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

Definition at line 359 of file app_meetme.c.

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

#define MAX_PIN   80

Definition at line 360 of file app_meetme.c.

Referenced by conf_exec().

#define MC_DATA_FORMAT   "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"

Referenced by meetme_cmd().

#define MC_HEADER_FORMAT   "%-14s %-14s %-10s %-8s %-8s %-6s\n"

Referenced by meetme_cmd().

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 84 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

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

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


Enumeration Type Documentation

anonymous enum
Enumerator:
ADMINFLAG_MUTED 

User is muted

ADMINFLAG_SELFMUTED 

User muted self

ADMINFLAG_KICKME 

User has been kicked

ADMINFLAG_T_REQUEST 

User has requested to speak

Definition at line 75 of file app_meetme.c.

00075      {
00076    ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
00077    ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
00078    ADMINFLAG_KICKME =    (1 << 3),  /*!< User has been kicked */
00079    /*! User has requested to speak */
00080    ADMINFLAG_T_REQUEST = (1 << 4),
00081 };

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_KEYEXIT 

If set asterisk will exit conference when key defined in p() option 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, treat 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 
CONFFLAG_SLA_TRUNK 
CONFFLAG_KICK_CONTINUE 

If set, the user should continue in the dialplan if kicked out

CONFFLAG_DURATION_STOP 
CONFFLAG_DURATION_LIMIT 
CONFFLAG_NO_AUDIO_UNTIL_UP 

Do not write any audio to this channel until the state is up.

Definition at line 107 of file app_meetme.c.

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

anonymous enum
Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_EXITKEYS 
OPT_ARG_DURATION_STOP 
OPT_ARG_DURATION_LIMIT 
OPT_ARG_MOH_CLASS 
OPT_ARG_ARRAY_SIZE 

Definition at line 168 of file app_meetme.c.

00168      {
00169    OPT_ARG_WAITMARKED = 0,
00170    OPT_ARG_EXITKEYS   = 1,
00171    OPT_ARG_DURATION_STOP = 2,
00172    OPT_ARG_DURATION_LIMIT = 3,
00173    OPT_ARG_MOH_CLASS = 4,
00174    OPT_ARG_ARRAY_SIZE = 5,
00175 };

anonymous enum
Enumerator:
SLA_TRUNK_OPT_MOH 

Definition at line 5212 of file app_meetme.c.

05212      {
05213    SLA_TRUNK_OPT_MOH = (1 << 0),
05214 };

anonymous enum
Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 5216 of file app_meetme.c.

05216      {
05217    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
05218    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
05219 };

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 362 of file app_meetme.c.

00362                    {
00363    CONF_HASJOIN,
00364    CONF_HASLEFT
00365 };

Enumerator:
ENTER 
LEAVE 

Definition at line 93 of file app_meetme.c.

00093                     {
00094    ENTER,
00095    LEAVE
00096 };

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 98 of file app_meetme.c.

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

Enumerator:
SLA_EVENT_HOLD 

A station has put the call on hold

SLA_EVENT_DIAL_STATE 

The state of a dial has changed

SLA_EVENT_RINGING_TRUNK 

The state of a ringing trunk has changed

SLA_EVENT_RELOAD 

A reload of configuration has been requested

SLA_EVENT_CHECK_RELOAD 

Poke the SLA thread so it can check if it can perform a reload

Definition at line 552 of file app_meetme.c.

00552                     {
00553    /*! A station has put the call on hold */
00554    SLA_EVENT_HOLD,
00555    /*! The state of a dial has changed */
00556    SLA_EVENT_DIAL_STATE,
00557    /*! The state of a ringing trunk has changed */
00558    SLA_EVENT_RINGING_TRUNK,
00559    /*! A reload of configuration has been requested */
00560    SLA_EVENT_RELOAD,
00561    /*! Poke the SLA thread so it can check if it can perform a reload */
00562    SLA_EVENT_CHECK_RELOAD,
00563 };

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

00462                      {
00463    /*! This means that any station can put it on hold, and any station
00464     * can retrieve the call from hold. */
00465    SLA_HOLD_OPEN,
00466    /*! This means that only the station that put the call on hold may
00467     * retrieve it from hold. */
00468    SLA_HOLD_PRIVATE,
00469 };

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 589 of file app_meetme.c.

Enumerator:
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 454 of file app_meetme.c.

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 449 of file app_meetme.c.

00449                           {
00450    ALL_TRUNK_REFS,
00451    INACTIVE_TRUNK_REFS,
00452 };

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 88 of file app_meetme.c.

00088                    {
00089    VOL_UP,
00090    VOL_DOWN
00091 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 5913 of file app_meetme.c.

static void __unreg_module ( void   )  [static]

Definition at line 5913 of file app_meetme.c.

static int acf_meetme_info ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 5768 of file app_meetme.c.

References acf_meetme_info_eval(), AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_conference::confno, ast_conference::list, LOG_ERROR, and parse().

05769 {
05770    struct ast_conference *conf;
05771    char *parse;
05772    int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
05773    AST_DECLARE_APP_ARGS(args,
05774       AST_APP_ARG(keyword);
05775       AST_APP_ARG(confno);
05776    );
05777 
05778    if (ast_strlen_zero(data)) {
05779       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
05780       return -1;
05781    }
05782 
05783    parse = ast_strdupa(data);
05784    AST_STANDARD_APP_ARGS(args, parse);
05785 
05786    if (ast_strlen_zero(args.keyword)) {
05787       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
05788       return -1;
05789    }
05790 
05791    if (ast_strlen_zero(args.confno)) {
05792       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
05793       return -1;
05794    }
05795 
05796    AST_LIST_LOCK(&confs);
05797    AST_LIST_TRAVERSE(&confs, conf, list) {
05798       if (!strcmp(args.confno, conf->confno)) {
05799          result = acf_meetme_info_eval(args.keyword, conf);
05800          break;
05801       }
05802    }
05803    AST_LIST_UNLOCK(&confs);
05804 
05805    if (result > -1) {
05806       snprintf(buf, len, "%d", result);
05807    } else if (result == -1) {
05808       snprintf(buf, len, "%s %s", "Error: invalid keyword:", args.keyword);
05809    } else if (result == -2) {
05810       snprintf(buf, len, "Error: conference (%s) not found", args.confno);
05811    }
05812 
05813    return 0;
05814 }

static int acf_meetme_info_eval ( char *  keyword,
struct ast_conference conf 
) [static]

Definition at line 5750 of file app_meetme.c.

References ast_conference::isdynamic, ast_conference::locked, ast_conference::start, and ast_conference::users.

Referenced by acf_meetme_info().

05751 {
05752    if (!strcasecmp("lock", keyword)) {
05753       return conf->locked;
05754    } else if (!strcasecmp("parties", keyword)) {
05755       return conf->users;
05756    } else if (!strcasecmp("activity", keyword)) {
05757       time_t now;
05758       now = time(NULL);
05759       return (now - conf->start);
05760    } else if (!strcasecmp("dynamic", keyword)) {
05761       return conf->isdynamic;
05762    } else {
05763       return -1;
05764    }
05765 
05766 }

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

Definition at line 3720 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_error(), astman_send_listack(), ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CONFFLAG_ADMIN, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_conference::confno, ast_conf_user::list, S_OR, ast_conf_user::talking, total, ast_conf_user::user_no, ast_conf_user::userflags, and ast_conference::userlist.

Referenced by load_module().

03721 {
03722    const char *actionid = astman_get_header(m, "ActionID");
03723    const char *conference = astman_get_header(m, "Conference");
03724    char idText[80] = "";
03725    struct ast_conference *cnf;
03726    struct ast_conf_user *user;
03727    int total = 0;
03728 
03729    if (!ast_strlen_zero(actionid))
03730       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
03731 
03732    if (AST_LIST_EMPTY(&confs)) {
03733       astman_send_error(s, m, "No active conferences.");
03734       return 0;
03735    }
03736 
03737    astman_send_listack(s, m, "Meetme user list will follow", "start");
03738 
03739    /* Find the right conference */
03740    AST_LIST_LOCK(&confs);
03741    AST_LIST_TRAVERSE(&confs, cnf, list) {
03742       /* If we ask for one particular, and this isn't it, skip it */
03743       if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
03744          continue;
03745 
03746       /* Show all the users */
03747       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03748          total++;
03749          astman_append(s,
03750          "Event: MeetmeList\r\n"
03751          "%s"
03752          "Conference: %s\r\n"
03753          "UserNumber: %d\r\n"
03754          "CallerIDNum: %s\r\n"
03755          "CallerIDName: %s\r\n"
03756          "Channel: %s\r\n"
03757          "Admin: %s\r\n"
03758          "Role: %s\r\n"
03759          "MarkedUser: %s\r\n"
03760          "Muted: %s\r\n"
03761          "Talking: %s\r\n"
03762          "\r\n",
03763          idText,
03764          cnf->confno,
03765          user->user_no,
03766          S_OR(user->chan->cid.cid_num, "<unknown>"),
03767          S_OR(user->chan->cid.cid_name, "<no name>"),
03768          user->chan->name,
03769          user->userflags & CONFFLAG_ADMIN ? "Yes" : "No",
03770          user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen",
03771          user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No",
03772          user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
03773          user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored"); 
03774       }
03775    }
03776    AST_LIST_UNLOCK(&confs);
03777    /* Send final confirmation */
03778    astman_append(s,
03779    "Event: MeetmeListComplete\r\n"
03780    "EventList: Complete\r\n"
03781    "ListItems: %d\r\n"
03782    "%s"
03783    "\r\n", total, idText);
03784    return 0;
03785 }

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

Definition at line 3702 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

03703 {
03704    return meetmemute(s, m, 1);
03705 }

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

Definition at line 3707 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

03708 {
03709    return meetmemute(s, m, 0);
03710 }

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

The MeetMeadmin application.

Definition at line 3432 of file app_meetme.c.

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

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

03432                                                             {
03433    char *params;
03434    struct ast_conference *cnf;
03435    struct ast_conf_user *user = NULL;
03436    AST_DECLARE_APP_ARGS(args,
03437       AST_APP_ARG(confno);
03438       AST_APP_ARG(command);
03439       AST_APP_ARG(user);
03440    );
03441 
03442    if (ast_strlen_zero(data)) {
03443       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
03444       return -1;
03445    }
03446 
03447    params = ast_strdupa(data);
03448    AST_STANDARD_APP_ARGS(args, params);
03449 
03450    if (!args.command) {
03451       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
03452       return -1;
03453    }
03454 
03455    AST_LIST_LOCK(&confs);
03456    AST_LIST_TRAVERSE(&confs, cnf, list) {
03457       if (!strcmp(cnf->confno, args.confno))
03458          break;
03459    }
03460 
03461    if (!cnf) {
03462       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
03463       AST_LIST_UNLOCK(&confs);
03464       return 0;
03465    }
03466 
03467    ast_atomic_fetchadd_int(&cnf->refcount, 1);
03468 
03469    if (args.user)
03470       user = find_user(cnf, args.user);
03471 
03472    switch (*args.command) {
03473    case 76: /* L: Lock */ 
03474       cnf->locked = 1;
03475       break;
03476    case 108: /* l: Unlock */ 
03477       cnf->locked = 0;
03478       break;
03479    case 75: /* K: kick all users */
03480       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03481          user->adminflags |= ADMINFLAG_KICKME;
03482       break;
03483    case 101: /* e: Eject last user*/
03484       user = AST_LIST_LAST(&cnf->userlist);
03485       if (!(user->userflags & CONFFLAG_ADMIN))
03486          user->adminflags |= ADMINFLAG_KICKME;
03487       else
03488          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
03489       break;
03490    case 77: /* M: Mute */ 
03491       if (user) {
03492          user->adminflags |= ADMINFLAG_MUTED;
03493       } else
03494          ast_log(LOG_NOTICE, "Specified User not found!\n");
03495       break;
03496    case 78: /* N: Mute all (non-admin) users */
03497       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03498          if (!(user->userflags & CONFFLAG_ADMIN))
03499             user->adminflags |= ADMINFLAG_MUTED;
03500       }
03501       break;               
03502    case 109: /* m: Unmute */ 
03503       if (user) {
03504          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03505       } else
03506          ast_log(LOG_NOTICE, "Specified User not found!\n");
03507       break;
03508    case 110: /* n: Unmute all users */
03509       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03510          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03511       break;
03512    case 107: /* k: Kick user */ 
03513       if (user)
03514          user->adminflags |= ADMINFLAG_KICKME;
03515       else
03516          ast_log(LOG_NOTICE, "Specified User not found!\n");
03517       break;
03518    case 118: /* v: Lower all users listen volume */
03519       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03520          tweak_listen_volume(user, VOL_DOWN);
03521       break;
03522    case 86: /* V: Raise all users listen volume */
03523       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03524          tweak_listen_volume(user, VOL_UP);
03525       break;
03526    case 115: /* s: Lower all users speaking volume */
03527       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03528          tweak_talk_volume(user, VOL_DOWN);
03529       break;
03530    case 83: /* S: Raise all users speaking volume */
03531       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03532          tweak_talk_volume(user, VOL_UP);
03533       break;
03534    case 82: /* R: Reset all volume levels */
03535       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03536          reset_volumes(user);
03537       break;
03538    case 114: /* r: Reset user's volume level */
03539       if (user)
03540          reset_volumes(user);
03541       else
03542          ast_log(LOG_NOTICE, "Specified User not found!\n");
03543       break;
03544    case 85: /* U: Raise user's listen volume */
03545       if (user)
03546          tweak_listen_volume(user, VOL_UP);
03547       else
03548          ast_log(LOG_NOTICE, "Specified User not found!\n");
03549       break;
03550    case 117: /* u: Lower user's listen volume */
03551       if (user)
03552          tweak_listen_volume(user, VOL_DOWN);
03553       else
03554          ast_log(LOG_NOTICE, "Specified User not found!\n");
03555       break;
03556    case 84: /* T: Raise user's talk volume */
03557       if (user)
03558          tweak_talk_volume(user, VOL_UP);
03559       else
03560          ast_log(LOG_NOTICE, "Specified User not found!\n");
03561       break;
03562    case 116: /* t: Lower user's talk volume */
03563       if (user) 
03564          tweak_talk_volume(user, VOL_DOWN);
03565       else 
03566          ast_log(LOG_NOTICE, "Specified User not found!\n");
03567       break;
03568    }
03569 
03570    AST_LIST_UNLOCK(&confs);
03571 
03572    dispose_conf(cnf);
03573    
03574    return 0;
03575 }

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

Definition at line 1570 of file app_meetme.c.

References ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread_stop, announce_listitem::announcetype, ao2_ref, ast_check_hangup(), ast_cond_wait(), ast_copy_string(), ast_filedelete(), ast_fileexists(), AST_LIST_APPEND_LIST, AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_HEAD_NOLOCK, AST_LIST_REMOVE_HEAD, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_streamfile(), ast_waitstream(), CONF_HASLEFT, announce_listitem::confchan, announce_listitem::confusers, get_announce_filename(), announce_listitem::language, LOG_DEBUG, and announce_listitem::namerecloc.

Referenced by conf_run().

01571 {
01572    struct announce_listitem *current;
01573    struct ast_conference *conf = data;
01574    int res = 0;
01575    char filename[PATH_MAX] = "";
01576    AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
01577    AST_LIST_HEAD_INIT_NOLOCK(&local_list);
01578 
01579    while (!conf->announcethread_stop) {
01580       ast_mutex_lock(&conf->announcelistlock);
01581       if (conf->announcethread_stop) {
01582          ast_mutex_unlock(&conf->announcelistlock);
01583          break;
01584       }
01585       if (AST_LIST_EMPTY(&conf->announcelist))
01586          ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
01587 
01588       AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
01589       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01590 
01591       ast_mutex_unlock(&conf->announcelistlock);
01592       if (conf->announcethread_stop) {
01593          break;
01594       }
01595 
01596       for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
01597          ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
01598          if (!ast_fileexists(current->namerecloc, NULL, NULL))
01599             continue;
01600          if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
01601             if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
01602                res = ast_waitstream(current->confchan, "");
01603             if (!res) {
01604                ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
01605                if (!ast_streamfile(current->confchan, filename, current->language))
01606                   ast_waitstream(current->confchan, "");
01607             }
01608          }
01609          if (current->announcetype == CONF_HASLEFT) {
01610             ast_filedelete(current->namerecloc, NULL);
01611          }
01612       }
01613    }
01614 
01615    /* thread marked to stop, clean up */
01616    while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
01617       ast_filedelete(current->namerecloc, NULL);
01618       ao2_ref(current, -1);
01619    }
01620    return NULL;
01621 }

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

Definition at line 4084 of file app_meetme.c.

References ast_answer(), and ast_indicate().

Referenced by run_station(), sla_handle_dial_state_event(), and sla_station_exec().

04085 {
04086    ast_answer(chan);
04087    ast_indicate(chan, -1);
04088 }

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

Find or create a conference.

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

Definition at line 828 of file app_meetme.c.

References ast_conference::announcethread, ast_conference::announcethreadlock, ast_atomic_fetchadd_int(), ast_calloc, ast_copy_string(), AST_FORMAT_SLINEAR, ast_free, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), AST_PTHREADT_NULL, ast_request(), ast_set_read_format(), ast_set_write_format(), ast_verb, ast_conference::chan, conf_map, ast_conference::confno, ast_conference::dahdiconf, ast_conference::fd, ast_channel::fds, ast_conference::isdynamic, ast_conference::listenlock, LOG_WARNING, ast_conference::maxusers, ast_conference::pin, ast_conference::pinadmin, ast_conference::playlock, ast_conference::recordthread, ast_conference::recordthreadlock, ast_conference::refcount, ast_conference::start, and ast_conference::uniqueid.

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

00829 {
00830    struct ast_conference *cnf;
00831    struct dahdi_confinfo dahdic = { 0, };
00832    int confno_int = 0;
00833 
00834    AST_LIST_LOCK(&confs);
00835 
00836    AST_LIST_TRAVERSE(&confs, cnf, list) {
00837       if (!strcmp(confno, cnf->confno)) 
00838          break;
00839    }
00840 
00841    if (cnf || (!make && !dynamic))
00842       goto cnfout;
00843 
00844    /* Make a new one */
00845    if (!(cnf = ast_calloc(1, sizeof(*cnf))))
00846       goto cnfout;
00847 
00848    ast_mutex_init(&cnf->playlock);
00849    ast_mutex_init(&cnf->listenlock);
00850    cnf->recordthread = AST_PTHREADT_NULL;
00851    ast_mutex_init(&cnf->recordthreadlock);
00852    cnf->announcethread = AST_PTHREADT_NULL;
00853    ast_mutex_init(&cnf->announcethreadlock);
00854    ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00855    ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00856    ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00857    ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid));
00858 
00859    /* Setup a new dahdi conference */
00860    dahdic.confno = -1;
00861    dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00862    cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
00863    if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
00864       ast_log(LOG_WARNING, "Unable to open pseudo device\n");
00865       if (cnf->fd >= 0)
00866          close(cnf->fd);
00867       ast_free(cnf);
00868       cnf = NULL;
00869       goto cnfout;
00870    }
00871 
00872    cnf->dahdiconf = dahdic.confno;
00873 
00874    /* Setup a new channel for playback of audio files */
00875    cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL);
00876    if (cnf->chan) {
00877       ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
00878       ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
00879       dahdic.chan = 0;
00880       dahdic.confno = cnf->dahdiconf;
00881       dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00882       if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
00883          ast_log(LOG_WARNING, "Error setting conference\n");
00884          if (cnf->chan)
00885             ast_hangup(cnf->chan);
00886          else
00887             close(cnf->fd);
00888 
00889          ast_free(cnf);
00890          cnf = NULL;
00891          goto cnfout;
00892       }
00893    }
00894 
00895    /* Fill the conference struct */
00896    cnf->start = time(NULL);
00897    cnf->maxusers = 0x7fffffff;
00898    cnf->isdynamic = dynamic ? 1 : 0;
00899    ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
00900    AST_LIST_INSERT_HEAD(&confs, cnf, list);
00901 
00902    /* Reserve conference number in map */
00903    if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
00904       conf_map[confno_int] = 1;
00905    
00906 cnfout:
00907    if (cnf)
00908       ast_atomic_fetchadd_int(&cnf->refcount, refcount);
00909 
00910    AST_LIST_UNLOCK(&confs);
00911 
00912    return cnf;
00913 }

static int can_write ( struct ast_channel chan,
int  confflags 
) [static]

Definition at line 1623 of file app_meetme.c.

References ast_channel::_state, AST_STATE_UP, and CONFFLAG_NO_AUDIO_UNTIL_UP.

Referenced by conf_run().

01624 {
01625    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01626       return 1;
01627    }
01628 
01629    return (chan->_state == AST_STATE_UP);
01630 }

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

Definition at line 662 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

Referenced by conf_play(), and conf_run().

00663 {
00664    int res;
00665    int x;
00666 
00667    while (len) {
00668       if (block) {
00669          x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
00670          res = ioctl(fd, DAHDI_IOMUX, &x);
00671       } else
00672          res = 0;
00673       if (res >= 0)
00674          res = write(fd, data, len);
00675       if (res < 1) {
00676          if (errno != EAGAIN) {
00677             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00678             return -1;
00679          } else
00680             return 0;
00681       }
00682       len -= res;
00683       data += res;
00684    }
00685 
00686    return 0;
00687 }

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

Definition at line 3579 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ast_conf_user::adminflags, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_conf_user::chan, ast_conf_user::list, LOG_NOTICE, LOG_WARNING, and ast_conference::userlist.

Referenced by load_module().

03579                                                                     {
03580    char *params;
03581    struct ast_conference *conf = NULL;
03582    struct ast_conf_user *user = NULL;
03583    AST_DECLARE_APP_ARGS(args,
03584       AST_APP_ARG(channel);
03585       AST_APP_ARG(command);
03586    );
03587 
03588    if (ast_strlen_zero(data)) {
03589       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
03590       return -1;
03591    }
03592    
03593    params = ast_strdupa(data);
03594    AST_STANDARD_APP_ARGS(args, params);
03595 
03596    if (!args.channel) {
03597       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
03598       return -1;
03599    }
03600 
03601    if (!args.command) {
03602       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
03603       return -1;
03604    }
03605 
03606    AST_LIST_LOCK(&confs);
03607    AST_LIST_TRAVERSE(&confs, conf, list) {
03608       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03609          if (!strcmp(user->chan->name, args.channel))
03610             break;
03611       }
03612    }
03613    
03614    if (!user) {
03615       ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
03616       AST_LIST_UNLOCK(&confs);
03617       return 0;
03618    }
03619    
03620    /* perform the specified action */
03621    switch (*args.command) {
03622       case 77: /* M: Mute */ 
03623          user->adminflags |= ADMINFLAG_MUTED;
03624          break;
03625       case 109: /* m: Unmute */ 
03626          user->adminflags &= ~ADMINFLAG_MUTED;
03627          break;
03628       case 107: /* k: Kick user */ 
03629          user->adminflags |= ADMINFLAG_KICKME;
03630          break;
03631       default: /* unknown command */
03632          ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
03633          break;
03634    }
03635 
03636    AST_LIST_UNLOCK(&confs);
03637    
03638    return 0;
03639 }

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

Definition at line 916 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(), ast_conf_user::list, strsep(), ast_conf_user::user_no, and ast_conference::userlist.

Referenced by meetme_cmd().

00917 {
00918    static char *cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
00919 
00920    int len = strlen(word);
00921    int which = 0;
00922    struct ast_conference *cnf = NULL;
00923    struct ast_conf_user *usr = NULL;
00924    char *confno = NULL;
00925    char usrno[50] = "";
00926    char *myline, *ret = NULL;
00927    
00928    if (pos == 1) {      /* Command */
00929       return ast_cli_complete(word, cmds, state);
00930    } else if (pos == 2) {  /* Conference Number */
00931       AST_LIST_LOCK(&confs);
00932       AST_LIST_TRAVERSE(&confs, cnf, list) {
00933          if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
00934             ret = cnf->confno;
00935             break;
00936          }
00937       }
00938       ret = ast_strdup(ret); /* dup before releasing the lock */
00939       AST_LIST_UNLOCK(&confs);
00940       return ret;
00941    } else if (pos == 3) {
00942       /* User Number || Conf Command option*/
00943       if (strstr(line, "mute") || strstr(line, "kick")) {
00944          if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
00945             return ast_strdup("all");
00946          which++;
00947          AST_LIST_LOCK(&confs);
00948 
00949          /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
00950          myline = ast_strdupa(line);
00951          if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
00952             while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
00953                ;
00954          }
00955          
00956          AST_LIST_TRAVERSE(&confs, cnf, list) {
00957             if (!strcmp(confno, cnf->confno))
00958                 break;
00959          }
00960 
00961          if (cnf) {
00962             /* Search for the user */
00963             AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
00964                snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
00965                if (!strncasecmp(word, usrno, len) && ++which > state)
00966                   break;
00967             }
00968          }
00969          AST_LIST_UNLOCK(&confs);
00970          return usr ? ast_strdup(usrno) : NULL;
00971       } else if (strstr(line, "list") && (state == 0))
00972          return ast_strdup("concise");
00973    }
00974 
00975    return NULL;
00976 }

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

The meetme() application.

Definition at line 3168 of file app_meetme.c.

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

Referenced by load_module().

03169 {
03170    int res = -1;
03171    char confno[MAX_CONFNUM] = "";
03172    int allowretry = 0;
03173    int retrycnt = 0;
03174    struct ast_conference *cnf = NULL;
03175    struct ast_flags confflags = {0}, config_flags = { 0 };
03176    int dynamic = 0;
03177    int empty = 0, empty_no_pin = 0;
03178    int always_prompt = 0;
03179    char *notdata, *info, the_pin[MAX_PIN] = "";
03180    AST_DECLARE_APP_ARGS(args,
03181       AST_APP_ARG(confno);
03182       AST_APP_ARG(options);
03183       AST_APP_ARG(pin);
03184    );
03185    char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
03186 
03187    if (ast_strlen_zero(data)) {
03188       allowretry = 1;
03189       notdata = "";
03190    } else {
03191       notdata = data;
03192    }
03193    
03194    if (chan->_state != AST_STATE_UP)
03195       ast_answer(chan);
03196 
03197    info = ast_strdupa(notdata);
03198 
03199    AST_STANDARD_APP_ARGS(args, info);  
03200 
03201    if (args.confno) {
03202       ast_copy_string(confno, args.confno, sizeof(confno));
03203       if (ast_strlen_zero(confno)) {
03204          allowretry = 1;
03205       }
03206    }
03207    
03208    if (args.pin)
03209       ast_copy_string(the_pin, args.pin, sizeof(the_pin));
03210 
03211    if (args.options) {
03212       ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
03213       dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
03214       if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
03215          strcpy(the_pin, "q");
03216 
03217       empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
03218       empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
03219       always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
03220    }
03221 
03222    do {
03223       if (retrycnt > 3)
03224          allowretry = 0;
03225       if (empty) {
03226          int i;
03227          struct ast_config *cfg;
03228          struct ast_variable *var;
03229          int confno_int;
03230 
03231          /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
03232          if ((empty_no_pin) || (!dynamic)) {
03233             cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03234             if (cfg) {
03235                var = ast_variable_browse(cfg, "rooms");
03236                while (var) {
03237                   if (!strcasecmp(var->name, "conf")) {
03238                      char *stringp = ast_strdupa(var->value);
03239                      if (stringp) {
03240                         char *confno_tmp = strsep(&stringp, "|,");
03241                         int found = 0;
03242                         if (!dynamic) {
03243                            /* For static:  run through the list and see if this conference is empty */
03244                            AST_LIST_LOCK(&confs);
03245                            AST_LIST_TRAVERSE(&confs, cnf, list) {
03246                               if (!strcmp(confno_tmp, cnf->confno)) {
03247                                  /* The conference exists, therefore it's not empty */
03248                                  found = 1;
03249                                  break;
03250                               }
03251                            }
03252                            AST_LIST_UNLOCK(&confs);
03253                            if (!found) {
03254                               /* At this point, we have a confno_tmp (static conference) that is empty */
03255                               if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
03256                                  /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
03257                                   * Case 2:  empty_no_pin and pin is blank (but not NULL)
03258                                   * Case 3:  not empty_no_pin
03259                                   */
03260                                  ast_copy_string(confno, confno_tmp, sizeof(confno));
03261                                  break;
03262                                  /* XXX the map is not complete (but we do have a confno) */
03263                               }
03264                            }
03265                         }
03266                      }
03267                   }
03268                   var = var->next;
03269                }
03270                ast_config_destroy(cfg);
03271             }
03272          }
03273 
03274          /* Select first conference number not in use */
03275          if (ast_strlen_zero(confno) && dynamic) {
03276             AST_LIST_LOCK(&confs);
03277             for (i = 0; i < ARRAY_LEN(conf_map); i++) {
03278                if (!conf_map[i]) {
03279                   snprintf(confno, sizeof(confno), "%d", i);
03280                   conf_map[i] = 1;
03281                   break;
03282                }
03283             }
03284             AST_LIST_UNLOCK(&confs);
03285          }
03286 
03287          /* Not found? */
03288          if (ast_strlen_zero(confno)) {
03289             res = ast_streamfile(chan, "conf-noempty", chan->language);
03290             if (!res)
03291                ast_waitstream(chan, "");
03292          } else {
03293             if (sscanf(confno, "%30d", &confno_int) == 1) {
03294                if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
03295                   res = ast_streamfile(chan, "conf-enteringno", chan->language);
03296                   if (!res) {
03297                      ast_waitstream(chan, "");
03298                      res = ast_say_digits(chan, confno_int, "", chan->language);
03299                   }
03300                }
03301             } else {
03302                ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
03303             }
03304          }
03305       }
03306 
03307       while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
03308          /* Prompt user for conference number */
03309          res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
03310          if (res < 0) {
03311             /* Don't try to validate when we catch an error */
03312             confno[0] = '\0';
03313             allowretry = 0;
03314             break;
03315          }
03316       }
03317       if (!ast_strlen_zero(confno)) {
03318          /* Check the validity of the conference */
03319          cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
03320             sizeof(the_pin), 1, &confflags);
03321          if (!cnf) {
03322             int too_early = 0;
03323             cnf = find_conf_realtime(chan, confno, 1, dynamic, 
03324                the_pin, sizeof(the_pin), 1, &confflags, optargs, &too_early);
03325             if (rt_schedule && too_early)
03326                allowretry = 0;
03327          }
03328 
03329          if (!cnf) {
03330             if (allowretry) {
03331                confno[0] = '\0';
03332                res = ast_streamfile(chan, "conf-invalid", chan->language);
03333                if (!res)
03334                   ast_waitstream(chan, "");
03335                res = -1;
03336             }
03337          } else {
03338             if ((!ast_strlen_zero(cnf->pin) &&
03339                  !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
03340                 (!ast_strlen_zero(cnf->pinadmin) &&
03341                  ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
03342                char pin[MAX_PIN] = "";
03343                int j;
03344 
03345                /* Allow the pin to be retried up to 3 times */
03346                for (j = 0; j < 3; j++) {
03347                   if (*the_pin && (always_prompt == 0)) {
03348                      ast_copy_string(pin, the_pin, sizeof(pin));
03349                      res = 0;
03350                   } else {
03351                      /* Prompt user for pin if pin is required */
03352                      res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
03353                   }
03354                   if (res >= 0) {
03355                      if (!strcasecmp(pin, cnf->pin) ||
03356                          (!ast_strlen_zero(cnf->pinadmin) &&
03357                           !strcasecmp(pin, cnf->pinadmin))) {
03358                         /* Pin correct */
03359                         allowretry = 0;
03360                         if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
03361                            ast_set_flag(&confflags, CONFFLAG_ADMIN);
03362                         /* Run the conference */
03363                         res = conf_run(chan, cnf, confflags.flags, optargs);
03364                         break;
03365                      } else {
03366                         /* Pin invalid */
03367                         if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
03368                            res = ast_waitstream(chan, AST_DIGIT_ANY);
03369                            ast_stopstream(chan);
03370                         }
03371                         else {
03372                            ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
03373                            break;
03374                         }
03375                         if (res < 0)
03376                            break;
03377                         pin[0] = res;
03378                         pin[1] = '\0';
03379                         res = -1;
03380                         if (allowretry)
03381                            confno[0] = '\0';
03382                      }
03383                   } else {
03384                      /* failed when getting the pin */
03385                      res = -1;
03386                      allowretry = 0;
03387                      /* see if we need to get rid of the conference */
03388                      break;
03389                   }
03390 
03391                   /* Don't retry pin with a static pin */
03392                   if (*the_pin && (always_prompt == 0)) {
03393                      break;
03394                   }
03395                }
03396             } else {
03397                /* No pin required */
03398                allowretry = 0;
03399 
03400                /* Run the conference */
03401                res = conf_run(chan, cnf, confflags.flags, optargs);
03402             }
03403             dispose_conf(cnf);
03404             cnf = NULL;
03405          }
03406       }
03407    } while (allowretry);
03408 
03409    if (cnf)
03410       dispose_conf(cnf);
03411    
03412    return res;
03413 }

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

Definition at line 1343 of file app_meetme.c.

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

Referenced by conf_run().

01344 {
01345    int x;
01346 
01347    /* read any frames that may be waiting on the channel
01348       and throw them away
01349    */
01350    if (chan) {
01351       struct ast_frame *f;
01352 
01353       /* when no frames are available, this will wait
01354          for 1 millisecond maximum
01355       */
01356       while (ast_waitfor(chan, 1)) {
01357          f = ast_read(chan);
01358          if (f)
01359             ast_frfree(f);
01360          else /* channel was hung up or something else happened */
01361             break;
01362       }
01363    }
01364 
01365    /* flush any data sitting in the pseudo channel */
01366    x = DAHDI_FLUSH_ALL;
01367    if (ioctl(fd, DAHDI_FLUSH, &x))
01368       ast_log(LOG_WARNING, "Error flushing channel\n");
01369 
01370 }

static int conf_free ( struct ast_conference conf  )  [static]

Definition at line 1374 of file app_meetme.c.

References ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethread_stop, ast_conference::announcethreadlock, ao2_ref, ast_cond_signal(), ast_filedelete(), AST_FRAME_BITS, ast_free, ast_frfree, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_translator_free_path(), ast_conference::chan, ast_conference::confno, EVENT_FLAG_CALL, ast_conference::fd, ast_conference::lchan, ast_conference::listenlock, manager_event, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, announce_listitem::namerecloc, ast_conference::origframe, ast_conference::playlock, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthreadlock, ast_conference::transframe, and ast_conference::transpath.

Referenced by dispose_conf().

01375 {
01376    int x;
01377    struct announce_listitem *item;
01378    
01379    AST_LIST_REMOVE(&confs, conf, list);
01380    manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01381 
01382    if (conf->recording == MEETME_RECORD_ACTIVE) {
01383       conf->recording = MEETME_RECORD_TERMINATE;
01384       AST_LIST_UNLOCK(&confs);
01385       while (1) {
01386          usleep(1);
01387          AST_LIST_LOCK(&confs);
01388          if (conf->recording == MEETME_RECORD_OFF)
01389             break;
01390          AST_LIST_UNLOCK(&confs);
01391       }
01392    }
01393 
01394    for (x = 0; x < AST_FRAME_BITS; x++) {
01395       if (conf->transframe[x])
01396          ast_frfree(conf->transframe[x]);
01397       if (conf->transpath[x])
01398          ast_translator_free_path(conf->transpath[x]);
01399    }
01400    if (conf->announcethread != AST_PTHREADT_NULL) {
01401       ast_mutex_lock(&conf->announcelistlock);
01402       conf->announcethread_stop = 1;
01403       ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01404       ast_cond_signal(&conf->announcelist_addition);
01405       ast_mutex_unlock(&conf->announcelistlock);
01406       pthread_join(conf->announcethread, NULL);
01407    
01408       while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01409          ast_filedelete(item->namerecloc, NULL);
01410          ao2_ref(item, -1);
01411       }
01412       ast_mutex_destroy(&conf->announcelistlock);
01413    }
01414    if (conf->origframe)
01415       ast_frfree(conf->origframe);
01416    if (conf->lchan)
01417       ast_hangup(conf->lchan);
01418    if (conf->chan)
01419       ast_hangup(conf->chan);
01420    if (conf->fd >= 0)
01421       close(conf->fd);
01422    if (conf->recordingfilename) {
01423       ast_free(conf->recordingfilename);
01424    }
01425    if (conf->recordingformat) {
01426       ast_free(conf->recordingformat);
01427    }
01428    ast_mutex_destroy(&conf->playlock);
01429    ast_mutex_destroy(&conf->listenlock);
01430    ast_mutex_destroy(&conf->recordthreadlock);
01431    ast_mutex_destroy(&conf->announcethreadlock);
01432    ast_free(conf);
01433 
01434    return 0;
01435 }

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

Definition at line 780 of file app_meetme.c.

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

Referenced by conf_run().

00781 {
00782    unsigned char *data;
00783    int len;
00784    int res = -1;
00785 
00786    if (!ast_check_hangup(chan))
00787       res = ast_autoservice_start(chan);
00788 
00789    AST_LIST_LOCK(&confs);
00790 
00791    switch(sound) {
00792    case ENTER:
00793       data = enter;
00794       len = sizeof(enter);
00795       break;
00796    case LEAVE:
00797       data = leave;
00798       len = sizeof(leave);
00799       break;
00800    default:
00801       data = NULL;
00802       len = 0;
00803    }
00804    if (data) {
00805       careful_write(conf->fd, data, len, 1);
00806    }
00807 
00808    AST_LIST_UNLOCK(&confs);
00809 
00810    if (!res) 
00811       ast_autoservice_stop(chan);
00812 }

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

Definition at line 1437 of file app_meetme.c.

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

Referenced by conf_run().

01439 {
01440    struct ast_conf_user *user;
01441 
01442    AST_LIST_TRAVERSE(&conf->userlist, user, list) {
01443       if (user == sender)
01444          continue;
01445       if (ast_write(user->chan, f) < 0)
01446          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01447    }
01448 }

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

Definition at line 1632 of file app_meetme.c.

References volume::actual, ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, announce_thread(), ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethreadlock, announce_listitem::announcetype, ao2_alloc, ao2_ref, ast_calloc, ast_channel_lock, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_cond_signal(), ast_config_AST_SPOOL_DIR, AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, ast_devstate_changed(), AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_silence(), ast_exists_extension(), ast_filedelete(), 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_free, ast_frfree, AST_FRIENDLY_OFFSET, ast_goto_if_exists(), ast_hangup(), ast_indicate(), AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LAST, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), ast_moh_stop(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_read(), ast_read_noaudio(), ast_realtime_require_field(), ast_record_review(), ast_request(), ast_safe_sleep(), ast_samp2tv(), ast_say_digits(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_translate(), ast_translator_build_path(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_update_realtime(), ast_verb, ast_waitfor_nandfds(), ast_waitstream(), ast_write(), ast_channel::audiohooks, buf, can_write(), careful_write(), ast_conference::chan, ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, conf_flush(), CONF_HASJOIN, CONF_HASLEFT, conf_play(), conf_queue_dtmf(), CONF_SIZE, conf_start_moh(), announce_listitem::confchan, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_DURATION_LIMIT, CONFFLAG_DURATION_STOP, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_KEYEXIT, CONFFLAG_KICK_CONTINUE, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_SLA_STATION, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, announce_listitem::confusers, ast_channel::context, ast_conf_user::dahdichannel, ast_conference::dahdiconf, ast_frame::data, ast_frame::datalen, volume::desired, dtmfstr, ast_conf_user::end_sound, ast_conference::endalert, ast_conference::endtime, ENTER, errno, EVENT_FLAG_CALL, exitcontext, f, ast_channel::fds, ast_frame::frametype, ast_conf_user::jointime, ast_conf_user::kicktime, announce_listitem::language, ast_conference::lchan, LEAVE, ast_conf_user::listen, ast_conference::listenlock, ast_conference::locked, LOG_WARNING, ast_channel::macrocontext, manager_event, ast_conference::markedusers, ast_conference::maxusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, ast_channel::monitor, announce_listitem::namerecloc, ast_conf_user::namerecloc, ast_frame::offset, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_EXITKEYS, OPT_ARG_MOH_CLASS, OPT_ARG_WAITMARKED, ast_conference::origframe, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_conf_user::play_warning, ast_conference::playlock, ast_frame::ptr, ast_channel::rawwriteformat, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, reset_volumes(), RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, S_OR, ast_frame::samples, sec, set_talk_volume(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_conf_user::start_time, strsep(), ast_frame::subclass, ast_conf_user::talk, ast_conf_user::talking, ast_channel::tech, THRESHOLD_SILENCE, ast_conf_user::timelimit, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_conference::uniqueid, ast_conf_user::user_no, ast_conf_user::userflags, ast_conference::userlist, ast_conference::users, var, VOL_DOWN, VOL_UP, ast_conf_user::warning_freq, and ast_conf_user::warning_sound.

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

01633 {
01634    struct ast_conf_user *user = NULL;
01635    struct ast_conf_user *usr = NULL;
01636    int fd;
01637    struct dahdi_confinfo dahdic, dahdic_empty;
01638    struct ast_frame *f;
01639    struct ast_channel *c;
01640    struct ast_frame fr;
01641    int outfd;
01642    int ms;
01643    int nfds;
01644    int res;
01645    int retrydahdi;
01646    int origfd;
01647    int musiconhold = 0;
01648    int firstpass = 0;
01649    int lastmarked = 0;
01650    int currentmarked = 0;
01651    int ret = -1;
01652    int x;
01653    int menu_active = 0;
01654    int talkreq_manager = 0;
01655    int using_pseudo = 0;
01656    int duration = 20;
01657    int hr, min, sec;
01658    int sent_event = 0;
01659    int checked = 0;
01660    int announcement_played = 0;
01661    struct timeval now;
01662    struct ast_dsp *dsp = NULL;
01663    struct ast_app *agi_app;
01664    char *agifile;
01665    const char *agifiledefault = "conf-background.agi", *tmpvar;
01666    char meetmesecs[30] = "";
01667    char exitcontext[AST_MAX_CONTEXT] = "";
01668    char recordingtmp[AST_MAX_EXTENSION] = "";
01669    char members[10] = "";
01670    int dtmf, opt_waitmarked_timeout = 0;
01671    time_t timeout = 0;
01672    struct dahdi_bufferinfo bi;
01673    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
01674    char *buf = __buf + AST_FRIENDLY_OFFSET;
01675    char *exitkeys = NULL;
01676    unsigned int calldurationlimit = 0;
01677    long timelimit = 0;
01678    long play_warning = 0;
01679    long warning_freq = 0;
01680    const char *warning_sound = NULL;
01681    const char *end_sound = NULL;
01682    char *parse;   
01683    long time_left_ms = 0;
01684    struct timeval nexteventts = { 0, };
01685    int to;
01686    int setusercount = 0;
01687 
01688    if (!(user = ast_calloc(1, sizeof(*user))))
01689       return ret;
01690 
01691    /* Possible timeout waiting for marked user */
01692    if ((confflags & CONFFLAG_WAITMARKED) &&
01693       !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
01694       (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
01695       (opt_waitmarked_timeout > 0)) {
01696       timeout = time(NULL) + opt_waitmarked_timeout;
01697    }
01698       
01699    if ((confflags & CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
01700       calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
01701       ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
01702    }
01703    
01704    if ((confflags & CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
01705       char *limit_str, *warning_str, *warnfreq_str;
01706       const char *var;
01707  
01708       parse = optargs[OPT_ARG_DURATION_LIMIT];
01709       limit_str = strsep(&parse, ":");
01710       warning_str = strsep(&parse, ":");
01711       warnfreq_str = parse;
01712  
01713       timelimit = atol(limit_str);
01714       if (warning_str)
01715          play_warning = atol(warning_str);
01716       if (warnfreq_str)
01717          warning_freq = atol(warnfreq_str);
01718  
01719       if (!timelimit) {
01720          timelimit = play_warning = warning_freq = 0;
01721          warning_sound = NULL;
01722       } else if (play_warning > timelimit) {       
01723          if (!warning_freq) {
01724             play_warning = 0;
01725          } else {
01726             while (play_warning > timelimit)
01727                play_warning -= warning_freq;
01728             if (play_warning < 1)
01729                play_warning = warning_freq = 0;
01730          }
01731       }
01732       
01733       ast_channel_lock(chan);
01734       if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
01735          var = ast_strdupa(var);
01736       }
01737       ast_channel_unlock(chan);
01738 
01739       warning_sound = var ? var : "timeleft";
01740       
01741       ast_channel_lock(chan);
01742       if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
01743          var = ast_strdupa(var);
01744       }
01745       ast_channel_unlock(chan);
01746       
01747       end_sound = var ? var : NULL;
01748          
01749       /* undo effect of S(x) in case they are both used */
01750       calldurationlimit = 0;
01751       /* more efficient do it like S(x) does since no advanced opts */
01752       if (!play_warning && !end_sound && timelimit) { 
01753          calldurationlimit = timelimit / 1000;
01754          timelimit = play_warning = warning_freq = 0;
01755       } else {
01756          ast_debug(2, "Limit Data for this call:\n");
01757          ast_debug(2, "- timelimit     = %ld\n", timelimit);
01758          ast_debug(2, "- play_warning  = %ld\n", play_warning);
01759          ast_debug(2, "- warning_freq  = %ld\n", warning_freq);
01760          ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
01761          ast_debug(2, "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
01762       }
01763    }
01764 
01765    /* Get exit keys */
01766    if ((confflags & CONFFLAG_KEYEXIT)) {
01767       if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
01768          exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
01769       else
01770          exitkeys = ast_strdupa("#"); /* Default */
01771    }
01772    
01773    if (confflags & CONFFLAG_RECORDCONF) {
01774       if (!conf->recordingfilename) {
01775          const char *var;
01776          ast_channel_lock(chan);
01777          if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
01778             conf->recordingfilename = ast_strdup(var);
01779          }
01780          if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
01781             conf->recordingformat = ast_strdup(var);
01782          }
01783          ast_channel_unlock(chan);
01784          if (!conf->recordingfilename) {
01785             snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
01786             conf->recordingfilename = ast_strdup(recordingtmp);
01787          }
01788          if (!conf->recordingformat) {
01789             conf->recordingformat = ast_strdup("wav");
01790          }
01791          ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
01792                 conf->confno, conf->recordingfilename, conf->recordingformat);
01793       }
01794    }
01795 
01796    ast_mutex_lock(&conf->recordthreadlock);
01797    if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
01798       ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
01799       ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
01800       dahdic.chan = 0;
01801       dahdic.confno = conf->dahdiconf;
01802       dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01803       if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
01804          ast_log(LOG_WARNING, "Error starting listen channel\n");
01805          ast_hangup(conf->lchan);
01806          conf->lchan = NULL;
01807       } else {
01808          ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
01809       }
01810    }
01811    ast_mutex_unlock(&conf->recordthreadlock);
01812 
01813    ast_mutex_lock(&conf->announcethreadlock);
01814    if ((conf->announcethread == AST_PTHREADT_NULL) && !(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
01815       ast_mutex_init(&conf->announcelistlock);
01816       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01817       ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
01818    }
01819    ast_mutex_unlock(&conf->announcethreadlock);
01820 
01821    time(&user->jointime);
01822    
01823    user->timelimit = timelimit;
01824    user->play_warning = play_warning;
01825    user->warning_freq = warning_freq;
01826    user->warning_sound = warning_sound;
01827    user->end_sound = end_sound;  
01828    
01829    if (calldurationlimit > 0) {
01830       time(&user->kicktime);
01831       user->kicktime = user->kicktime + calldurationlimit;
01832    }
01833    
01834    if (ast_tvzero(user->start_time))
01835       user->start_time = ast_tvnow();
01836    time_left_ms = user->timelimit;
01837    
01838    if (user->timelimit) {
01839       nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
01840       nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
01841    }
01842 
01843    if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
01844       /* Sorry, but this conference is locked! */  
01845       if (!ast_streamfile(chan, "conf-locked", chan->language))
01846          ast_waitstream(chan, "");
01847       goto outrun;
01848    }
01849 
01850       ast_mutex_lock(&conf->playlock);
01851 
01852    if (AST_LIST_EMPTY(&conf->userlist))
01853       user->user_no = 1;
01854    else
01855       user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
01856 
01857    if (rt_schedule && conf->maxusers)
01858       if (conf->users >= conf->maxusers) {
01859          /* Sorry, but this confernce has reached the participant limit! */   
01860          if (!ast_streamfile(chan, "conf-full", chan->language))
01861             ast_waitstream(chan, "");
01862          ast_mutex_unlock(&conf->playlock);
01863          user->user_no = 0;
01864          goto outrun;
01865       }
01866 
01867    AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
01868 
01869    user->chan = chan;
01870    user->userflags = confflags;
01871    user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
01872    user->talking = -1;
01873 
01874    ast_mutex_unlock(&conf->playlock);
01875 
01876    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
01877       char destdir[PATH_MAX];
01878 
01879       snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
01880 
01881       if (ast_mkdir(destdir, 0777) != 0) {
01882          ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
01883          goto outrun;
01884       }
01885 
01886       snprintf(user->namerecloc, sizeof(user->namerecloc),
01887           "%s/meetme-username-%s-%d", destdir,
01888           conf->confno, user->user_no);
01889       if (confflags & CONFFLAG_INTROUSERNOREVIEW)
01890          res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
01891       else
01892          res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
01893       if (res == -1)
01894          goto outrun;
01895    }
01896 
01897    ast_mutex_lock(&conf->playlock);
01898 
01899    if (confflags & CONFFLAG_MARKEDUSER)
01900       conf->markedusers++;
01901    conf->users++;
01902    if (rt_log_members) {
01903       /* Update table */
01904       snprintf(members, sizeof(members), "%d", conf->users);
01905       ast_realtime_require_field("meetme",
01906          "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
01907          "members", RQ_UINTEGER1, strlen(members),
01908          NULL);
01909       ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
01910    }
01911    setusercount = 1;
01912 
01913    /* This device changed state now - if this is the first user */
01914    if (conf->users == 1)
01915       ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
01916 
01917    ast_mutex_unlock(&conf->playlock);
01918 
01919    /* return the unique ID of the conference */
01920    pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
01921 
01922    if (confflags & CONFFLAG_EXIT_CONTEXT) {
01923       ast_channel_lock(chan);
01924       if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
01925          ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
01926       } else if (!ast_strlen_zero(chan->macrocontext)) {
01927          ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
01928       } else {
01929          ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
01930       }
01931       ast_channel_unlock(chan);
01932    }
01933 
01934    if (!(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
01935       if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
01936          if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
01937             ast_waitstream(chan, "");
01938       if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
01939          if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
01940             ast_waitstream(chan, "");
01941    }
01942 
01943    if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
01944       int keepplaying = 1;
01945 
01946       if (conf->users == 2) { 
01947          if (!ast_streamfile(chan, "conf-onlyone", chan->language)) {
01948             res = ast_waitstream(chan, AST_DIGIT_ANY);
01949             ast_stopstream(chan);
01950             if (res > 0)
01951                keepplaying = 0;
01952             else if (res == -1)
01953                goto outrun;
01954          }
01955       } else { 
01956          if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
01957             res = ast_waitstream(chan, AST_DIGIT_ANY);
01958             ast_stopstream(chan);
01959             if (res > 0)
01960                keepplaying = 0;
01961             else if (res == -1)
01962                goto outrun;
01963          }
01964          if (keepplaying) {
01965             res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
01966             if (res > 0)
01967                keepplaying = 0;
01968             else if (res == -1)
01969                goto outrun;
01970          }
01971          if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
01972             res = ast_waitstream(chan, AST_DIGIT_ANY);
01973             ast_stopstream(chan);
01974             if (res > 0)
01975                keepplaying = 0;
01976             else if (res == -1) 
01977                goto outrun;
01978          }
01979       }
01980    }
01981 
01982    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01983       /* We're leaving this alone until the state gets changed to up */
01984       ast_indicate(chan, -1);
01985    }
01986 
01987    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
01988       ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
01989       goto outrun;
01990    }
01991 
01992    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
01993       ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
01994       goto outrun;
01995    }
01996 
01997    retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
01998    user->dahdichannel = !retrydahdi;
01999 
02000  dahdiretry:
02001    origfd = chan->fds[0];
02002    if (retrydahdi) {
02003       /* open pseudo in non-blocking mode */
02004       fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
02005       if (fd < 0) {
02006          ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
02007          goto outrun;
02008       }
02009       using_pseudo = 1;
02010       /* Setup buffering information */
02011       memset(&bi, 0, sizeof(bi));
02012       bi.bufsize = CONF_SIZE / 2;
02013       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
02014       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
02015       bi.numbufs = audio_buffers;
02016       if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
02017          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
02018          close(fd);
02019          goto outrun;
02020       }
02021       x = 1;
02022       if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
02023          ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
02024          close(fd);
02025          goto outrun;
02026       }
02027       nfds = 1;
02028    } else {
02029       /* XXX Make sure we're not running on a pseudo channel XXX */
02030       fd = chan->fds[0];
02031       nfds = 0;
02032    }
02033    memset(&dahdic, 0, sizeof(dahdic));
02034    memset(&dahdic_empty, 0, sizeof(dahdic_empty));
02035    /* Check to see if we're in a conference... */
02036    dahdic.chan = 0;  
02037    if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
02038       ast_log(LOG_WARNING, "Error getting conference\n");
02039       close(fd);
02040       goto outrun;
02041    }
02042    if (dahdic.confmode) {
02043       /* Whoa, already in a conference...  Retry... */
02044       if (!retrydahdi) {
02045          ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
02046          retrydahdi = 1;
02047          goto dahdiretry;
02048       }
02049    }
02050    memset(&dahdic, 0, sizeof(dahdic));
02051    /* Add us to the conference */
02052    dahdic.chan = 0;  
02053    dahdic.confno = conf->dahdiconf;
02054 
02055    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02056       struct announce_listitem *item;
02057       if (!(item = ao2_alloc(sizeof(*item), NULL)))
02058          return -1;
02059       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02060       ast_copy_string(item->language, chan->language, sizeof(item->language));
02061       item->confchan = conf->chan;
02062       item->confusers = conf->users;
02063       item->announcetype = CONF_HASJOIN;
02064       ast_mutex_lock(&conf->announcelistlock);
02065       ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
02066       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02067       ast_cond_signal(&conf->announcelist_addition);
02068       ast_mutex_unlock(&conf->announcelistlock);
02069 
02070       while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
02071          ;
02072       }
02073       ao2_ref(item, -1);
02074    }
02075 
02076    if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers)
02077       dahdic.confmode = DAHDI_CONF_CONF;
02078    else if (confflags & CONFFLAG_MONITOR)
02079       dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02080    else if (confflags & CONFFLAG_TALKER)
02081       dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02082    else 
02083       dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02084 
02085    if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02086       ast_log(LOG_WARNING, "Error setting conference\n");
02087       close(fd);
02088       goto outrun;
02089    }
02090    ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf);
02091 
02092    if (!sent_event) {
02093       manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
02094                  "Channel: %s\r\n"
02095                  "Uniqueid: %s\r\n"
02096             "Meetme: %s\r\n"
02097             "Usernum: %d\r\n"
02098             "CallerIDnum: %s\r\n"
02099                   "CallerIDname: %s\r\n",
02100                   chan->name, chan->uniqueid, conf->confno, 
02101             user->user_no,
02102             S_OR(user->chan->cid.cid_num, "<unknown>"),
02103             S_OR(user->chan->cid.cid_name, "<unknown>")
02104             );
02105       sent_event = 1;
02106    }
02107 
02108    if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
02109       firstpass = 1;
02110       if (!(confflags & CONFFLAG_QUIET))
02111          if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
02112             conf_play(chan, conf, ENTER);
02113    }
02114 
02115    conf_flush(fd, chan);
02116 
02117    if (confflags & CONFFLAG_AGI) {
02118       /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
02119          or use default filename of conf-background.agi */
02120 
02121       ast_channel_lock(chan);
02122       if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
02123          agifile = ast_strdupa(tmpvar);
02124       } else {
02125          agifile = ast_strdupa(agifiledefault);
02126       }
02127       ast_channel_unlock(chan);
02128       
02129       if (user->dahdichannel) {
02130          /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
02131          x = 1;
02132          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02133       }
02134       /* Find a pointer to the agi app and execute the script */
02135       agi_app = pbx_findapp("agi");
02136       if (agi_app) {
02137          ret = pbx_exec(chan, agi_app, agifile);
02138       } else {
02139          ast_log(LOG_WARNING, "Could not find application (agi)\n");
02140          ret = -2;
02141       }
02142       if (user->dahdichannel) {
02143          /*  Remove CONFMUTE mode on DAHDI channel */
02144          x = 0;
02145          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02146       }
02147    } else {
02148       if (user->dahdichannel && (confflags & CONFFLAG_STARMENU)) {
02149          /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
02150          x = 1;
02151          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02152       }  
02153       if (confflags & (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER) && !(dsp = ast_dsp_new())) {
02154          ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
02155          res = -1;
02156       }
02157       for (;;) {
02158          int menu_was_active = 0;
02159 
02160          outfd = -1;
02161          ms = -1;
02162          now = ast_tvnow();
02163 
02164          if (rt_schedule) {
02165             if (now.tv_sec % 60 == 0) {
02166                if (!checked) {
02167                   if (now.tv_sec >= conf->endtime) {
02168                      goto outrun;
02169                   }
02170 
02171                   if (!announcement_played && conf->endalert) {
02172                      if (now.tv_sec + conf->endalert >= conf->endtime) {
02173                         if (!ast_streamfile(chan, "conf-will-end-in", chan->language))
02174                            ast_waitstream(chan, "");
02175                         ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language);
02176                         if (!ast_streamfile(chan, "minutes", chan->language))
02177                            ast_waitstream(chan, "");
02178                         announcement_played = 1;
02179                      }
02180                   }
02181                   checked = 1;
02182                   
02183                }
02184             } else {
02185                checked = 0;
02186             }
02187          }
02188 
02189          if (user->kicktime && (user->kicktime <= now.tv_sec)) 
02190             break;
02191   
02192          to = -1;
02193          if (user->timelimit) {
02194             int minutes = 0, seconds = 0, remain = 0;
02195  
02196             to = ast_tvdiff_ms(nexteventts, now);
02197             if (to < 0)
02198                to = 0;
02199             time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
02200             if (time_left_ms < to)
02201                to = time_left_ms;
02202    
02203             if (time_left_ms <= 0) {
02204                if (user->end_sound) {                 
02205                   res = ast_streamfile(chan, user->end_sound, chan->language);
02206                   res = ast_waitstream(chan, "");
02207                }
02208                break;
02209             }
02210             
02211             if (!to) {
02212                if (time_left_ms >= 5000) {                  
02213                   
02214                   remain = (time_left_ms + 500) / 1000;
02215                   if (remain / 60 >= 1) {
02216                      minutes = remain / 60;
02217                      seconds = remain % 60;
02218                   } else {
02219                      seconds = remain;
02220                   }
02221                   
02222                   /* force the time left to round up if appropriate */
02223                   if (user->warning_sound && user->play_warning) {
02224                      if (!strcmp(user->warning_sound, "timeleft")) {
02225                         
02226                         res = ast_streamfile(chan, "vm-youhave", chan->language);
02227                         res = ast_waitstream(chan, "");
02228                         if (minutes) {
02229                            res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL);
02230                            res = ast_streamfile(chan, "queue-minutes", chan->language);
02231                            res = ast_waitstream(chan, "");
02232                         }
02233                         if (seconds) {
02234                            res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL);
02235                            res = ast_streamfile(chan, "queue-seconds", chan->language);
02236                            res = ast_waitstream(chan, "");
02237                         }
02238                      } else {
02239                         res = ast_streamfile(chan, user->warning_sound, chan->language);
02240                         res = ast_waitstream(chan, "");
02241                      }
02242                   }
02243                }
02244                if (user->warning_freq)
02245                   nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
02246                else
02247                   nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
02248             }
02249          }
02250 
02251          now = ast_tvnow();
02252          if (timeout && now.tv_sec >= timeout)
02253             break;
02254 
02255          /* if we have just exited from the menu, and the user had a channel-driver
02256             volume adjustment, restore it
02257          */
02258          if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
02259             set_talk_volume(user, user->listen.desired);
02260 
02261          menu_was_active = menu_active;
02262 
02263          currentmarked = conf->markedusers;
02264          if (!(confflags & CONFFLAG_QUIET) &&
02265              (confflags & CONFFLAG_MARKEDUSER) &&
02266              (confflags & CONFFLAG_WAITMARKED) &&
02267              lastmarked == 0) {
02268             if (currentmarked == 1 && conf->users > 1) {
02269                ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
02270                if (conf->users - 1 == 1) {
02271                   if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
02272                      ast_waitstream(chan, "");
02273                } else {
02274                   if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
02275                      ast_waitstream(chan, "");
02276                }
02277             }
02278             if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
02279                if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
02280                   ast_waitstream(chan, "");
02281          }
02282 
02283          /* Update the struct with the actual confflags */
02284          user->userflags = confflags;
02285 
02286          if (confflags & CONFFLAG_WAITMARKED) {
02287             if (currentmarked == 0) {
02288                if (lastmarked != 0) {
02289                   if (!(confflags & CONFFLAG_QUIET))
02290                      if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
02291                         ast_waitstream(chan, "");
02292                   if (confflags & CONFFLAG_MARKEDEXIT) {
02293                      if (confflags & CONFFLAG_KICK_CONTINUE)
02294                         ret = 0;
02295                      break;
02296                   } else {
02297                      dahdic.confmode = DAHDI_CONF_CONF;
02298                      if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02299                         ast_log(LOG_WARNING, "Error setting conference\n");
02300                         close(fd);
02301                         goto outrun;
02302                      }
02303                   }
02304                }
02305                if (!musiconhold && (confflags & CONFFLAG_MOH)) {
02306                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02307                   musiconhold = 1;
02308                }
02309             } else if (currentmarked >= 1 && lastmarked == 0) {
02310                /* Marked user entered, so cancel timeout */
02311                timeout = 0;
02312                if (confflags & CONFFLAG_MONITOR)
02313                   dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02314                else if (confflags & CONFFLAG_TALKER)
02315                   dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02316                else
02317                   dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02318                if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02319                   ast_log(LOG_WARNING, "Error setting conference\n");
02320                   close(fd);
02321                   goto outrun;
02322                }
02323                if (musiconhold && (confflags & CONFFLAG_MOH)) {
02324                   ast_moh_stop(chan);
02325                   musiconhold = 0;
02326                }
02327                if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
02328                   if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
02329                      ast_waitstream(chan, "");
02330                   conf_play(chan, conf, ENTER);
02331                }
02332             }
02333          }
02334 
02335          /* trying to add moh for single person conf */
02336          if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
02337             if (conf->users == 1) {
02338                if (!musiconhold) {
02339                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02340                   musiconhold = 1;
02341                } 
02342             } else {
02343                if (musiconhold) {
02344                   ast_moh_stop(chan);
02345                   musiconhold = 0;
02346                }
02347             }
02348          }
02349          
02350          /* Leave if the last marked user left */
02351          if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
02352             if (confflags & CONFFLAG_KICK_CONTINUE)
02353                ret = 0;
02354             else
02355                ret = -1;
02356             break;
02357          }
02358    
02359          /* Check if my modes have changed */
02360 
02361          /* If I should be muted but am still talker, mute me */
02362          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
02363             dahdic.confmode ^= DAHDI_CONF_TALKER;
02364             if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02365                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02366                ret = -1;
02367                break;
02368             }
02369 
02370             manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
02371                   "Channel: %s\r\n"
02372                   "Uniqueid: %s\r\n"
02373                   "Meetme: %s\r\n"
02374                   "Usernum: %i\r\n"
02375                   "Status: on\r\n",
02376                   chan->name, chan->uniqueid, conf->confno, user->user_no);
02377          }
02378 
02379          /* If I should be un-muted but am not talker, un-mute me */
02380          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
02381             dahdic.confmode |= DAHDI_CONF_TALKER;
02382             if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02383                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02384                ret = -1;
02385                break;
02386             }
02387 
02388             manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
02389                   "Channel: %s\r\n"
02390                   "Uniqueid: %s\r\n"
02391                   "Meetme: %s\r\n"
02392                   "Usernum: %i\r\n"
02393                   "Status: off\r\n",
02394                   chan->name, chan->uniqueid, conf->confno, user->user_no);
02395          }
02396          
02397          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
02398             (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
02399             talkreq_manager = 1;
02400 
02401             manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 
02402                      "Channel: %s\r\n"
02403                            "Uniqueid: %s\r\n"
02404                            "Meetme: %s\r\n"
02405                            "Usernum: %i\r\n"
02406                            "Status: on\r\n",
02407                            chan->name, chan->uniqueid, conf->confno, user->user_no);
02408          }
02409 
02410          
02411          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
02412             !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
02413             talkreq_manager = 0;
02414             manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 
02415                      "Channel: %s\r\n"
02416                            "Uniqueid: %s\r\n"
02417                            "Meetme: %s\r\n"
02418                            "Usernum: %i\r\n"
02419                            "Status: off\r\n",
02420                           chan->name, chan->uniqueid, conf->confno, user->user_no);
02421          }
02422          
02423          /* If I have been kicked, exit the conference */
02424          if (user->adminflags & ADMINFLAG_KICKME) {
02425             /* You have been kicked. */
02426             if (!(confflags & CONFFLAG_QUIET) && 
02427                !ast_streamfile(chan, "conf-kicked", chan->language)) {
02428                ast_waitstream(chan, "");
02429             }
02430             ret = 0;
02431             break;
02432          }
02433 
02434          /* Perform an extra hangup check just in case */
02435          if (ast_check_hangup(chan))
02436             break;
02437 
02438          c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
02439 
02440          if (c) {
02441             char dtmfstr[2] = "";
02442 
02443             if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) {
02444                if (using_pseudo) {
02445                   /* Kill old pseudo */
02446                   close(fd);
02447                   using_pseudo = 0;
02448                }
02449                ast_debug(1, "Ooh, something swapped out under us, starting over\n");
02450                retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0);
02451                user->dahdichannel = !retrydahdi;
02452                goto dahdiretry;
02453             }
02454             if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
02455                f = ast_read_noaudio(c);
02456             else
02457                f = ast_read(c);
02458             if (!f)
02459                break;
02460             if (f->frametype == AST_FRAME_DTMF) {
02461                dtmfstr[0] = f->subclass;
02462                dtmfstr[1] = '\0';
02463             }
02464 
02465             if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
02466                if (user->talk.actual)
02467                   ast_frame_adjust_volume(f, user->talk.actual);
02468 
02469                if (confflags & (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER)) {
02470                   int totalsilence;
02471 
02472                   if (user->talking == -1)
02473                      user->talking = 0;
02474 
02475                   res = ast_dsp_silence(dsp, f, &totalsilence);
02476                   if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
02477                      user->talking = 1;
02478                      if (confflags & CONFFLAG_MONITORTALKER)
02479                         manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
02480                               "Channel: %s\r\n"
02481                               "Uniqueid: %s\r\n"
02482                               "Meetme: %s\r\n"
02483                               "Usernum: %d\r\n"
02484                               "Status: on\r\n",
02485                               chan->name, chan->uniqueid, conf->confno, user->user_no);
02486                   }
02487                   if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
02488                      user->talking = 0;
02489                      if (confflags & CONFFLAG_MONITORTALKER)
02490                         manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
02491                               "Channel: %s\r\n"
02492                               "Uniqueid: %s\r\n"
02493                               "Meetme: %s\r\n"
02494                               "Usernum: %d\r\n"
02495                               "Status: off\r\n",
02496                               chan->name, chan->uniqueid, conf->confno, user->user_no);
02497                   }
02498                }
02499                if (using_pseudo) {
02500                   /* Absolutely do _not_ use careful_write here...
02501                      it is important that we read data from the channel
02502                      as fast as it arrives, and feed it into the conference.
02503                      The buffering in the pseudo channel will take care of any
02504                      timing differences, unless they are so drastic as to lose
02505                      audio frames (in which case carefully writing would only
02506                      have delayed the audio even further).
02507                   */
02508                   /* As it turns out, we do want to use careful write.  We just
02509                      don't want to block, but we do want to at least *try*
02510                      to write out all the samples.
02511                    */
02512                   if (user->talking && !(confflags & CONFFLAG_OPTIMIZETALKER)) {
02513                      careful_write(fd, f->data.ptr, f->datalen, 0);
02514                   }
02515                }
02516             } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
02517                if (confflags & CONFFLAG_PASS_DTMF)
02518                   conf_queue_dtmf(conf, user, f);
02519                if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
02520                   ast_log(LOG_WARNING, "Error setting conference\n");
02521                   close(fd);
02522                   ast_frfree(f);
02523                   goto outrun;
02524                }
02525 
02526                /* if we are entering the menu, and the user has a channel-driver
02527                   volume adjustment, clear it
02528                */
02529                if (!menu_active && user->talk.desired && !user->talk.actual)
02530                   set_talk_volume(user, 0);
02531 
02532                if (musiconhold) {
02533                      ast_moh_stop(chan);
02534                }
02535                if ((confflags & CONFFLAG_ADMIN)) {
02536                   /* Admin menu */
02537                   if (!menu_active) {
02538                      menu_active = 1;
02539                      /* Record this sound! */
02540                      if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
02541                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02542                         ast_stopstream(chan);
02543                      } else 
02544                         dtmf = 0;
02545                   } else 
02546                      dtmf = f->subclass;
02547                   if (dtmf) {
02548                      switch(dtmf) {
02549                      case '1': /* Un/Mute */
02550                         menu_active = 0;
02551 
02552                         /* for admin, change both admin and use flags */
02553                         if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
02554                            user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02555                         else
02556                            user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02557 
02558                         if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02559                            if (!ast_streamfile(chan, "conf-muted", chan->language))
02560                               ast_waitstream(chan, "");
02561                         } else {
02562                            if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02563                               ast_waitstream(chan, "");
02564                         }
02565                         break;
02566                      case '2': /* Un/Lock the Conference */
02567                         menu_active = 0;
02568                         if (conf->locked) {
02569                            conf->locked = 0;
02570                            if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
02571                               ast_waitstream(chan, "");
02572                         } else {
02573                            conf->locked = 1;
02574                            if (!ast_streamfile(chan, "conf-lockednow", chan->language))
02575                               ast_waitstream(chan, "");
02576                         }
02577                         break;
02578                      case '3': /* Eject last user */
02579                         menu_active = 0;
02580                         usr = AST_LIST_LAST(&conf->userlist);
02581                         if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
02582                            if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02583                               ast_waitstream(chan, "");
02584                         } else 
02585                            usr->adminflags |= ADMINFLAG_KICKME;
02586                         ast_stopstream(chan);
02587                         break;   
02588                      case '4':
02589                         tweak_listen_volume(user, VOL_DOWN);
02590                         break;
02591                      case '6':
02592                         tweak_listen_volume(user, VOL_UP);
02593                         break;
02594                      case '7':
02595                         tweak_talk_volume(user, VOL_DOWN);
02596                         break;
02597                      case '8':
02598                         menu_active = 0;
02599                         break;
02600                      case '9':
02601                         tweak_talk_volume(user, VOL_UP);
02602                         break;
02603                      default:
02604                         menu_active = 0;
02605                         /* Play an error message! */
02606                         if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02607                            ast_waitstream(chan, "");
02608                         break;
02609                      }
02610                   }
02611                } else {
02612                   /* User menu */
02613                   if (!menu_active) {
02614                      menu_active = 1;
02615                      if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
02616                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02617                         ast_stopstream(chan);
02618                      } else
02619                         dtmf = 0;
02620                   } else 
02621                      dtmf = f->subclass;
02622                   if (dtmf) {
02623                      switch(dtmf) {
02624                      case '1': /* Un/Mute */
02625                         menu_active = 0;
02626 
02627                         /* user can only toggle the self-muted state */
02628                         user->adminflags ^= ADMINFLAG_SELFMUTED;
02629 
02630                         /* they can't override the admin mute state */
02631                         if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02632                            if (!ast_streamfile(chan, "conf-muted", chan->language))
02633                               ast_waitstream(chan, "");
02634                         } else {
02635                            if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02636                               ast_waitstream(chan, "");
02637                         }
02638                         break;
02639                      case '2':
02640                         menu_active = 0;
02641                         if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
02642                            user->adminflags |= ADMINFLAG_T_REQUEST;
02643                            
02644                         if (user->adminflags & ADMINFLAG_T_REQUEST)
02645                            if (!ast_streamfile(chan, "beep", chan->language))
02646                               ast_waitstream(chan, "");
02647                         break;
02648                      case '4':
02649                         tweak_listen_volume(user, VOL_DOWN);
02650                         break;
02651                      case '6':
02652                         tweak_listen_volume(user, VOL_UP);
02653                         break;
02654                      case '7':
02655                         tweak_talk_volume(user, VOL_DOWN);
02656                         break;
02657                      case '8':
02658                         menu_active = 0;
02659                         break;
02660                      case '9':
02661                         tweak_talk_volume(user, VOL_UP);
02662                         break;
02663                      default:
02664                         menu_active = 0;
02665                         if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02666                            ast_waitstream(chan, "");
02667                         break;
02668                      }
02669                   }
02670                }
02671                if (musiconhold)
02672                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02673 
02674                if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02675                   ast_log(LOG_WARNING, "Error setting conference\n");
02676                   close(fd);
02677                   ast_frfree(f);
02678                   goto outrun;
02679                }
02680 
02681                conf_flush(fd, chan);
02682             /* Since this option could absorb dtmf meant for the previous (menu), we have to check this one last */
02683             } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
02684                if (confflags & CONFFLAG_PASS_DTMF)
02685                   conf_queue_dtmf(conf, user, f);
02686 
02687                if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
02688                   ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
02689                   ret = 0;
02690                   ast_frfree(f);
02691                   break;
02692                } else {
02693                   ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
02694                }
02695             } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) {
02696                pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
02697                   
02698                if (confflags & CONFFLAG_PASS_DTMF)
02699                   conf_queue_dtmf(conf, user, f);
02700                ret = 0;
02701                ast_frfree(f);
02702                break;
02703             } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
02704                && confflags & CONFFLAG_PASS_DTMF) {
02705                conf_queue_dtmf(conf, user, f);
02706             } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
02707                switch (f->subclass) {
02708                case AST_CONTROL_HOLD:
02709                   sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
02710                   break;
02711                default:
02712                   break;
02713                }
02714             } else if (f->frametype == AST_FRAME_NULL) {
02715                /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
02716             } else {
02717                ast_debug(1, 
02718                   "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
02719                   chan->name, f->frametype, f->subclass);
02720             }
02721             ast_frfree(f);
02722          } else if (outfd > -1) {
02723             res = read(outfd, buf, CONF_SIZE);
02724             if (res > 0) {
02725                memset(&fr, 0, sizeof(fr));
02726                fr.frametype = AST_FRAME_VOICE;
02727                fr.subclass = AST_FORMAT_SLINEAR;
02728                fr.datalen = res;
02729                fr.samples = res / 2;
02730                fr.data.ptr = buf;
02731                fr.offset = AST_FRIENDLY_OFFSET;
02732                if (!user->listen.actual &&
02733                   ((confflags & CONFFLAG_MONITOR) ||
02734                    (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
02735                    (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
02736                    )) {
02737                   int idx;
02738                   for (idx = 0; idx < AST_FRAME_BITS; idx++)
02739                      if (chan->rawwriteformat & (1 << idx))
02740                         break;
02741                   if (idx >= AST_FRAME_BITS)
02742                      goto bailoutandtrynormal;
02743                   ast_mutex_lock(&conf->listenlock);
02744                   if (!conf->transframe[idx]) {
02745                      if (conf->origframe) {
02746                         if (!conf->transpath[idx])
02747                            conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR);
02748                         if (conf->transpath[idx]) {
02749                            conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
02750                            if (!conf->transframe[idx])
02751                               conf->transframe[idx] = &ast_null_frame;
02752                         }
02753                      }
02754                   }
02755                   if (conf->transframe[idx]) {
02756                      if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
02757                          can_write(chan, confflags)) {
02758                         struct ast_frame *cur;
02759                         
02760                         /* the translator may have returned a list of frames, so
02761                            write each one onto the channel
02762                         */
02763                         for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
02764                            if (ast_write(chan, cur)) {
02765                               ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02766                               break;
02767                            }
02768                         }
02769                      }
02770                   } else {
02771                      ast_mutex_unlock(&conf->listenlock);
02772                      goto bailoutandtrynormal;
02773                   }
02774                   ast_mutex_unlock(&conf->listenlock);
02775                } else {
02776 bailoutandtrynormal:             
02777                   if (user->listen.actual)
02778                      ast_frame_adjust_volume(&fr, user->listen.actual);
02779                   if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
02780                      ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02781                   }
02782                }
02783             } else 
02784                ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
02785          }
02786          lastmarked = currentmarked;
02787       }
02788    }
02789 
02790    if (musiconhold)
02791       ast_moh_stop(chan);
02792    
02793    if (using_pseudo)
02794       close(fd);
02795    else {
02796       /* Take out of conference */
02797       dahdic.chan = 0;  
02798       dahdic.confno = 0;
02799       dahdic.confmode = 0;
02800       if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02801          ast_log(LOG_WARNING, "Error setting conference\n");
02802       }
02803    }
02804 
02805    reset_volumes(user);
02806 
02807    if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
02808       conf_play(chan, conf, LEAVE);
02809 
02810    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02811       struct announce_listitem *item;
02812       if (!(item = ao2_alloc(sizeof(*item), NULL)))
02813          return -1;
02814       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02815       ast_copy_string(item->language, chan->language, sizeof(item->language));
02816       item->confchan = conf->chan;
02817       item->confusers = conf->users;
02818       item->announcetype = CONF_HASLEFT;
02819       ast_mutex_lock(&conf->announcelistlock);
02820       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02821       ast_cond_signal(&conf->announcelist_addition);
02822       ast_mutex_unlock(&conf->announcelistlock);
02823    } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) {
02824       /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
02825       ast_filedelete(user->namerecloc, NULL);
02826    }
02827 
02828  outrun:
02829    AST_LIST_LOCK(&confs);
02830 
02831    if (dsp)
02832       ast_dsp_free(dsp);
02833    
02834    if (user->user_no) { /* Only cleanup users who really joined! */
02835       now = ast_tvnow();
02836       hr = (now.tv_sec - user->jointime) / 3600;
02837       min = ((now.tv_sec - user->jointime) % 3600) / 60;
02838       sec = (now.tv_sec - user->jointime) % 60;
02839 
02840       if (sent_event) {
02841          manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
02842                   "Channel: %s\r\n"
02843                   "Uniqueid: %s\r\n"
02844                   "Meetme: %s\r\n"
02845                   "Usernum: %d\r\n"
02846                   "CallerIDNum: %s\r\n"
02847                   "CallerIDName: %s\r\n"
02848                   "Duration: %ld\r\n",
02849                   chan->name, chan->uniqueid, conf->confno, 
02850                   user->user_no,
02851                   S_OR(user->chan->cid.cid_num, "<unknown>"),
02852                   S_OR(user->chan->cid.cid_name, "<unknown>"),
02853                   (long)(now.tv_sec - user->jointime));
02854       }
02855 
02856       if (setusercount) {
02857          conf->users--;
02858          if (rt_log_members) {
02859             /* Update table */
02860             snprintf(members, sizeof(members), "%d", conf->users);
02861             ast_realtime_require_field("meetme",
02862                "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
02863                "members", RQ_UINTEGER1, strlen(members),
02864                NULL);
02865             ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
02866          }
02867          if (confflags & CONFFLAG_MARKEDUSER) 
02868             conf->markedusers--;
02869       }
02870       /* Remove ourselves from the list */
02871       AST_LIST_REMOVE(&conf->userlist, user, list);
02872 
02873       /* Change any states */
02874       if (!conf->users)
02875          ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
02876       
02877       /* Return the number of seconds the user was in the conf */
02878       snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
02879       pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
02880    }
02881    ast_free(user);
02882    AST_LIST_UNLOCK(&confs);
02883 
02884    return ret;
02885 }

static void conf_start_moh ( struct ast_channel chan,
const char *  musicclass 
) [static]

Definition at line 1540 of file app_meetme.c.

References ast_channel_lock, ast_channel_unlock, ast_moh_start(), ast_strdupa, and ast_string_field_set.

Referenced by conf_run().

01541 {
01542    char *original_moh;
01543 
01544    ast_channel_lock(chan);
01545    original_moh = ast_strdupa(chan->musicclass);
01546    ast_string_field_set(chan, musicclass, musicclass);
01547    ast_channel_unlock(chan);
01548 
01549    ast_moh_start(chan, original_moh, NULL);
01550 
01551    ast_channel_lock(chan);
01552    ast_string_field_set(chan, musicclass, original_moh);
01553    ast_channel_unlock(chan);
01554 }

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

The MeetmeCount application.

Definition at line 3123 of file app_meetme.c.

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

Referenced by load_module().

03124 {
03125    int res = 0;
03126    struct ast_conference *conf;
03127    int count;
03128    char *localdata;
03129    char val[80] = "0"; 
03130    AST_DECLARE_APP_ARGS(args,
03131       AST_APP_ARG(confno);
03132       AST_APP_ARG(varname);
03133    );
03134 
03135    if (ast_strlen_zero(data)) {
03136       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
03137       return -1;
03138    }
03139    
03140    if (!(localdata = ast_strdupa(data)))
03141       return -1;
03142 
03143    AST_STANDARD_APP_ARGS(args, localdata);
03144    
03145    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
03146 
03147    if (conf) {
03148       count = conf->users;
03149       dispose_conf(conf);
03150       conf = NULL;
03151    } else
03152       count = 0;
03153 
03154    if (!ast_strlen_zero(args.varname)) {
03155       /* have var so load it and exit */
03156       snprintf(val, sizeof(val), "%d", count);
03157       pbx_builtin_setvar_helper(chan, args.varname, val);
03158    } else {
03159       if (chan->_state != AST_STATE_UP)
03160          ast_answer(chan);
03161       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
03162    }
03163 
03164    return res;
03165 }

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

Definition at line 5179 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

05180 {
05181    struct sla_trunk_ref *trunk_ref;
05182 
05183    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
05184       return NULL;
05185 
05186    trunk_ref->trunk = trunk;
05187 
05188    return trunk_ref;
05189 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 5390 of file app_meetme.c.

References ast_context_remove_extension(), ast_free, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, AST_MAX_APP, AST_MAX_EXTENSION, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_string_field_free_memory, ast_strlen_zero(), sla_station::autocontext, exten, sla_trunk::name, sla_station::name, PRIORITY_HINT, sla_registrar, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_build_station(), and sla_destroy().

05391 {
05392    struct sla_trunk_ref *trunk_ref;
05393 
05394    if (!ast_strlen_zero(station->autocontext)) {
05395       AST_RWLIST_RDLOCK(&sla_trunks);
05396       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05397          char exten[AST_MAX_EXTENSION];
05398          char hint[AST_MAX_APP];
05399          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05400          snprintf(hint, sizeof(hint), "SLA:%s", exten);
05401          ast_context_remove_extension(station->autocontext, exten, 
05402             1, sla_registrar);
05403          ast_context_remove_extension(station->autocontext, hint, 
05404             PRIORITY_HINT, sla_registrar);
05405       }
05406       AST_RWLIST_UNLOCK(&sla_trunks);
05407    }
05408 
05409    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
05410       ast_free(trunk_ref);
05411 
05412    ast_string_field_free_memory(station);
05413    ast_free(station);
05414 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 5376 of file app_meetme.c.

References ast_context_remove_extension(), ast_free, AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, ast_strlen_zero(), sla_trunk::autocontext, sla_registrar, and sla_trunk::stations.

Referenced by sla_build_trunk(), and sla_destroy().

05377 {
05378    struct sla_station_ref *station_ref;
05379 
05380    if (!ast_strlen_zero(trunk->autocontext))
05381       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
05382 
05383    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
05384       ast_free(station_ref);
05385 
05386    ast_string_field_free_memory(trunk);
05387    ast_free(trunk);
05388 }

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

Definition at line 4891 of file app_meetme.c.

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

Referenced by sla_station_exec().

04892 {
04893    struct dial_trunk_args *args = data;
04894    struct ast_dial *dial;
04895    char *tech, *tech_data;
04896    enum ast_dial_result dial_res;
04897    char conf_name[MAX_CONFNUM];
04898    struct ast_conference *conf;
04899    struct ast_flags conf_flags = { 0 };
04900    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
04901    const char *cid_name = NULL, *cid_num = NULL;
04902 
04903    if (!(dial = ast_dial_create())) {
04904       ast_mutex_lock(args->cond_lock);
04905       ast_cond_signal(args->cond);
04906       ast_mutex_unlock(args->cond_lock);
04907       return NULL;
04908    }
04909 
04910    tech_data = ast_strdupa(trunk_ref->trunk->device);
04911    tech = strsep(&tech_data, "/");
04912    if (ast_dial_append(dial, tech, tech_data) == -1) {
04913       ast_mutex_lock(args->cond_lock);
04914       ast_cond_signal(args->cond);
04915       ast_mutex_unlock(args->cond_lock);
04916       ast_dial_destroy(dial);
04917       return NULL;
04918    }
04919 
04920    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
04921       cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
04922       ast_free(trunk_ref->chan->cid.cid_name);
04923       trunk_ref->chan->cid.cid_name = NULL;
04924    }
04925    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
04926       cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
04927       ast_free(trunk_ref->chan->cid.cid_num);
04928       trunk_ref->chan->cid.cid_num = NULL;
04929    }
04930 
04931    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
04932 
04933    if (cid_name)
04934       trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
04935    if (cid_num)
04936       trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
04937 
04938    if (dial_res != AST_DIAL_RESULT_TRYING) {
04939       ast_mutex_lock(args->cond_lock);
04940       ast_cond_signal(args->cond);
04941       ast_mutex_unlock(args->cond_lock);
04942       ast_dial_destroy(dial);
04943       return NULL;
04944    }
04945 
04946    for (;;) {
04947       unsigned int done = 0;
04948       switch ((dial_res = ast_dial_state(dial))) {
04949       case AST_DIAL_RESULT_ANSWERED:
04950          trunk_ref->trunk->chan = ast_dial_answered(dial);
04951       case AST_DIAL_RESULT_HANGUP:
04952       case AST_DIAL_RESULT_INVALID:
04953       case AST_DIAL_RESULT_FAILED:
04954       case AST_DIAL_RESULT_TIMEOUT:
04955       case AST_DIAL_RESULT_UNANSWERED:
04956          done = 1;
04957       case AST_DIAL_RESULT_TRYING:
04958       case AST_DIAL_RESULT_RINGING:
04959       case AST_DIAL_RESULT_PROGRESS:
04960       case AST_DIAL_RESULT_PROCEEDING:
04961          break;
04962       }
04963       if (done)
04964          break;
04965    }
04966 
04967    if (!trunk_ref->trunk->chan) {
04968       ast_mutex_lock(args->cond_lock);
04969       ast_cond_signal(args->cond);
04970       ast_mutex_unlock(args->cond_lock);
04971       ast_dial_join(dial);
04972       ast_dial_destroy(dial);
04973       return NULL;
04974    }
04975 
04976    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04977    ast_set_flag(&conf_flags, 
04978       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
04979       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
04980    conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan);
04981 
04982    ast_mutex_lock(args->cond_lock);
04983    ast_cond_signal(args->cond);
04984    ast_mutex_unlock(args->cond_lock);
04985 
04986    if (conf) {
04987       conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
04988       dispose_conf(conf);
04989       conf = NULL;
04990    }
04991 
04992    /* If the trunk is going away, it is definitely now IDLE. */
04993    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04994 
04995    trunk_ref->trunk->chan = NULL;
04996    trunk_ref->trunk->on_hold = 0;
04997 
04998    ast_dial_join(dial);
04999    ast_dial_destroy(dial);
05000 
05001    return NULL;
05002 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Definition at line 1522 of file app_meetme.c.

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

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

01523 {
01524    int res = 0;
01525    int confno_int = 0;
01526 
01527    AST_LIST_LOCK(&confs);
01528    if (ast_atomic_dec_and_test(&conf->refcount)) {
01529       /* Take the conference room number out of an inuse state */
01530       if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01531          conf_map[confno_int] = 0;
01532       conf_free(conf);
01533       res = 1;
01534    }
01535    AST_LIST_UNLOCK(&confs);
01536 
01537    return res;
01538 }

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

Definition at line 3025 of file app_meetme.c.

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

Referenced by conf_exec(), and count_exec().

03027 {
03028    struct ast_config *cfg;
03029    struct ast_variable *var;
03030    struct ast_flags config_flags = { 0 };
03031    struct ast_conference *cnf;
03032    char *parse;
03033    AST_DECLARE_APP_ARGS(args,
03034       AST_APP_ARG(confno);
03035       AST_APP_ARG(pin);
03036       AST_APP_ARG(pinadmin);
03037    );
03038 
03039    /* Check first in the conference list */
03040    ast_debug(1, "The requested confno is '%s'?\n", confno);
03041    AST_LIST_LOCK(&confs);
03042    AST_LIST_TRAVERSE(&confs, cnf, list) {
03043       ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
03044       if (!strcmp(confno, cnf->confno)) 
03045          break;
03046    }
03047    if (cnf) {
03048       cnf->refcount += refcount;
03049    }
03050    AST_LIST_UNLOCK(&confs);
03051 
03052    if (!cnf) {
03053       if (dynamic) {
03054          /* No need to parse meetme.conf */
03055          ast_debug(1, "Building dynamic conference '%s'\n", confno);
03056          if (dynamic_pin) {
03057             if (dynamic_pin[0] == 'q') {
03058                /* Query the user to enter a PIN */
03059                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
03060                   return NULL;
03061             }
03062             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
03063          } else {
03064             cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
03065          }
03066       } else {
03067          /* Check the config */
03068          cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03069          if (!cfg) {
03070             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
03071             return NULL;
03072          }
03073          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
03074             if (strcasecmp(var->name, "conf"))
03075                continue;
03076             
03077             if (!(parse = ast_strdupa(var->value)))
03078                return NULL;
03079             
03080             AST_STANDARD_APP_ARGS(args, parse);
03081             ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
03082             if (!strcasecmp(args.confno, confno)) {
03083                /* Bingo it's a valid conference */
03084                cnf = build_conf(args.confno,
03085                      S_OR(args.pin, ""),
03086                      S_OR(args.pinadmin, ""),
03087                      make, dynamic, refcount, chan);
03088                break;
03089             }
03090          }
03091          if (!var) {
03092             ast_debug(1, "%s isn't a valid conference\n", confno);
03093          }
03094          ast_config_destroy(cfg);
03095       }
03096    } else if (dynamic_pin) {
03097       /* Correct for the user selecting 'D' instead of 'd' to have
03098          someone join into a conference that has already been created
03099          with a pin. */
03100       if (dynamic_pin[0] == 'q')
03101          dynamic_pin[0] = '\0';
03102    }
03103 
03104    if (cnf) {
03105       if (confflags && !cnf->chan &&
03106           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03107           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03108          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03109          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03110       }
03111       
03112       if (confflags && !cnf->chan &&
03113           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03114          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03115          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03116       }
03117    }
03118 
03119    return cnf;
03120 }

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,
char *  optargs[],
int *  too_early 
) [static, read]

Definition at line 2887 of file app_meetme.c.

References ast_clear_flag, ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), ast_mktime(), ast_strdupa, ast_streamfile(), ast_strftime(), ast_test_flag, ast_tvnow(), ast_variables_destroy(), ast_waitstream(), build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, ast_conference::confno, DATE_FORMAT, ast_conference::endalert, ast_conference::endtime, ast_conference::list, LOG_WARNING, ast_conference::maxusers, ast_variable::name, ast_variable::next, ast_conference::refcount, ast_variable::value, and var.

Referenced by conf_exec().

02890 {
02891    struct ast_variable *var;
02892    struct ast_conference *cnf;
02893 
02894    *too_early = 0;
02895 
02896    /* Check first in the conference list */
02897    AST_LIST_LOCK(&confs);
02898    AST_LIST_TRAVERSE(&confs, cnf, list) {
02899       if (!strcmp(confno, cnf->confno)) 
02900          break;
02901    }
02902    if (cnf) {
02903       cnf->refcount += refcount;
02904    }
02905    AST_LIST_UNLOCK(&confs);
02906 
02907    if (!cnf) {
02908       char *pin = NULL, *pinadmin = NULL; /* For temp use */
02909       int maxusers = 0;
02910       struct timeval now;
02911       char currenttime[19] = "";
02912       char eatime[19] = "";
02913       char useropts[32] = "";
02914       char adminopts[32] = "";
02915       struct ast_tm tm, etm;
02916       struct timeval endtime = { .tv_sec = 0 };
02917 
02918       if (rt_schedule) {
02919          now = ast_tvnow();
02920 
02921          ast_localtime(&now, &tm, NULL);
02922          ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02923 
02924          ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
02925 
02926          var = ast_load_realtime("meetme", "confno",
02927             confno, "starttime <= ", currenttime, "endtime >= ",
02928             currenttime, NULL);
02929 
02930          if (!var && fuzzystart) {
02931             now = ast_tvnow();
02932             now.tv_sec += fuzzystart;
02933 
02934             ast_localtime(&now, &tm, NULL);
02935             ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02936             var = ast_load_realtime("meetme", "confno",
02937                confno, "starttime <= ", currenttime, "endtime >= ",
02938                currenttime, NULL);
02939          }
02940 
02941          if (!var && earlyalert) {
02942             now = ast_tvnow();
02943             now.tv_sec += earlyalert;
02944             ast_localtime(&now, &etm, NULL);
02945             ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
02946             var = ast_load_realtime("meetme", "confno",
02947                confno, "starttime <= ", eatime, "endtime >= ",
02948                currenttime, NULL);
02949             if (var)
02950                *too_early = 1;
02951          }
02952 
02953       } else
02954           var = ast_load_realtime("meetme", "confno", confno, NULL);
02955 
02956       if (!var)
02957          return NULL;
02958 
02959       if (rt_schedule && *too_early) {
02960          /* Announce that the caller is early and exit */
02961          if (!ast_streamfile(chan, "conf-has-not-started", chan->language))
02962             ast_waitstream(chan, "");
02963          ast_variables_destroy(var);
02964          return NULL;
02965       }
02966 
02967       while (var) {
02968          if (!strcasecmp(var->name, "pin")) {
02969             pin = ast_strdupa(var->value);
02970          } else if (!strcasecmp(var->name, "adminpin")) {
02971             pinadmin = ast_strdupa(var->value);
02972          } else if (!strcasecmp(var->name, "opts")) {
02973             ast_copy_string(useropts, var->value, sizeof(useropts));
02974          } else if (!strcasecmp(var->name, "maxusers")) {
02975             maxusers = atoi(var->value);
02976          } else if (!strcasecmp(var->name, "adminopts")) {
02977             ast_copy_string(adminopts, var->value, sizeof(adminopts));
02978          } else if (!strcasecmp(var->name, "endtime")) {
02979             union {
02980                struct ast_tm atm;
02981                struct tm tm;
02982             } t = { { 0, }, };
02983             strptime(var->value, "%Y-%m-%d %H:%M:%S", &t.tm);
02984             /* strptime does not determine if a time is
02985              * in DST or not.  Set tm_isdst to -1 to 
02986              * allow ast_mktime to adjust for DST 
02987              * if needed */
02988             t.tm.tm_isdst = -1; 
02989             endtime = ast_mktime(&t.atm, NULL);
02990          }
02991 
02992          var = var->next;
02993       }
02994 
02995       ast_variables_destroy(var);
02996 
02997       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
02998 
02999       if (cnf) {
03000          cnf->maxusers = maxusers;
03001          cnf->endalert = endalert;
03002          cnf->endtime = endtime.tv_sec;
03003       }
03004    }
03005 
03006    if (cnf) {
03007       if (confflags && !cnf->chan &&
03008           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03009           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03010          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03011          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03012       }
03013       
03014       if (confflags && !cnf->chan &&
03015           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03016          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03017          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03018       }
03019    }
03020 
03021    return cnf;
03022 }

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

Definition at line 3415 of file app_meetme.c.

References AST_LIST_TRAVERSE, ast_conf_user::list, ast_conf_user::user_no, and ast_conference::userlist.

Referenced by admin_exec().

03416 {
03417    struct ast_conf_user *user = NULL;
03418    int cid;
03419    
03420    sscanf(callerident, "%30i", &cid);
03421    if (conf && callerident) {
03422       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03423          if (cid == user->user_no)
03424             return user;
03425       }
03426    }
03427    return NULL;
03428 }

static const char* get_announce_filename ( enum announcetypes  type  )  [static]

Definition at line 1556 of file app_meetme.c.

References CONF_HASJOIN, and CONF_HASLEFT.

Referenced by announce_thread().

01557 {
01558    switch (type) {
01559    case CONF_HASLEFT:
01560       return "conf-hasleft";
01561       break;
01562    case CONF_HASJOIN:
01563       return "conf-hasjoin";
01564       break;
01565    default:
01566       return "";
01567    }
01568 }

static char* istalking ( int  x  )  [static]

Definition at line 652 of file app_meetme.c.

Referenced by meetme_cmd().

00653 {
00654    if (x > 0)
00655       return "(talking)";
00656    else if (x < 0)
00657       return "(unmonitored)";
00658    else 
00659       return "(not talking)";
00660 }

static int load_config ( int  reload  )  [static]

Definition at line 5832 of file app_meetme.c.

References ast_log(), load_config_meetme(), LOG_NOTICE, SLA_EVENT_RELOAD, sla_load_config(), and sla_queue_event().

Referenced by load_module(), and reload().

05833 {
05834    load_config_meetme();
05835 
05836    if (reload) {
05837       sla_queue_event(SLA_EVENT_RELOAD);
05838       ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
05839          "and will be completed when the system is idle.\n");
05840       return 0;
05841    }
05842    
05843    return sla_load_config(0);
05844 }

static void load_config_meetme ( void   )  [static]

Definition at line 3874 of file app_meetme.c.

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

Referenced by load_config().

03875 {
03876    struct ast_config *cfg;
03877    struct ast_flags config_flags = { 0 };
03878    const char *val;
03879 
03880    if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags)))
03881       return;
03882 
03883    audio_buffers = DEFAULT_AUDIO_BUFFERS;
03884 
03885    /*  Scheduling support is off by default */
03886    rt_schedule = 0;
03887    fuzzystart = 0;
03888    earlyalert = 0;
03889    endalert = 0;
03890 
03891    /*  Logging of participants defaults to ON for compatibility reasons */
03892    rt_log_members = 1;  
03893 
03894    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03895       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
03896          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03897          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03898       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
03899          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03900             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
03901          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03902       }
03903       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03904          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03905    }
03906 
03907    if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
03908       rt_schedule = ast_true(val);
03909    if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
03910       rt_log_members = ast_true(val);
03911    if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
03912       if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
03913          ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
03914          fuzzystart = 0;
03915       } 
03916    }
03917    if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
03918       if ((sscanf(val, "%30d", &earlyalert) != 1)) {
03919          ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
03920          earlyalert = 0;
03921       } 
03922    }
03923    if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
03924       if ((sscanf(val, "%30d", &endalert) != 1)) {
03925          ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
03926          endalert = 0;
03927       } 
03928    }
03929 
03930    ast_config_destroy(cfg);
03931 }

static int load_module ( void   )  [static]

Definition at line 5872 of file app_meetme.c.

References action_meetmelist(), action_meetmemute(), action_meetmeunmute(), admin_exec(), ARRAY_LEN, ast_cli_register_multiple(), ast_custom_function_register, ast_devstate_prov_add(), ast_manager_register, ast_manager_register2(), ast_realtime_require_field(), ast_register_application, channel_admin_exec(), conf_exec(), count_exec(), EVENT_FLAG_CALL, EVENT_FLAG_REPORTING, load_config(), meetmestate(), RQ_UINTEGER1, RQ_UINTEGER2, sla_state(), sla_station_exec(), and sla_trunk_exec().

05873 {
05874    int res = 0;
05875 
05876    res |= load_config(0);
05877 
05878    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05879    res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 
05880                 action_meetmemute, "Mute a Meetme user");
05881    res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 
05882                 action_meetmeunmute, "Unmute a Meetme user");
05883    res |= ast_manager_register2("MeetmeList", EVENT_FLAG_REPORTING, 
05884                 action_meetmelist, "List participants in a conference", mandescr_meetmelist);
05885    res |= ast_register_application(app4, channel_admin_exec, synopsis4, descrip4);
05886    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
05887    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
05888    res |= ast_register_application(app, conf_exec, synopsis, descrip);
05889    res |= ast_register_application(slastation_app, sla_station_exec,
05890                slastation_synopsis, slastation_desc);
05891    res |= ast_register_application(slatrunk_app, sla_trunk_exec,
05892                slatrunk_synopsis, slatrunk_desc);
05893 
05894    res |= ast_devstate_prov_add("Meetme", meetmestate);
05895    res |= ast_devstate_prov_add("SLA", sla_state);
05896 
05897    res |= ast_custom_function_register(&meetme_info_acf);
05898    ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
05899 
05900    return res;
05901 }

static char* meetme_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 978 of file app_meetme.c.

References admin_exec(), ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_debug, ast_free, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_str_append(), ast_str_create(), ast_str_set(), ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd(), CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_cli_args::fd, ast_conference::isdynamic, istalking(), ast_conf_user::jointime, ast_cli_args::line, ast_conference::locked, ast_conference::markedusers, MAX_CONFNUM, MC_DATA_FORMAT, MC_HEADER_FORMAT, ast_cli_args::n, ast_cli_args::pos, S_OR, sec, ast_conference::start, ast_str::str, ast_conf_user::talking, total, ast_cli_entry::usage, ast_conf_user::user_no, ast_conf_user::userflags, ast_conference::userlist, ast_conference::users, and ast_cli_args::word.

00979 {
00980    /* Process the command */
00981    struct ast_conference *cnf;
00982    struct ast_conf_user *user;
00983    int hr, min, sec;
00984    int i = 0, total = 0;
00985    time_t now;
00986    struct ast_str *cmdline = NULL;
00987 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s  %-8s  %-6s\n"
00988 #define MC_DATA_FORMAT "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s  %-6s\n"
00989 
00990    switch (cmd) {
00991    case CLI_INIT:
00992       e->command = "meetme";
00993       e->usage =
00994          "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
00995          "       Executes a command for the conference or on a conferee\n";
00996       return NULL;
00997    case CLI_GENERATE:
00998       return complete_meetmecmd(a->line, a->word, a->pos, a->n);
00999    }
01000 
01001    if (a->argc > 8)
01002       ast_cli(a->fd, "Invalid Arguments.\n");
01003    /* Check for length so no buffer will overflow... */
01004    for (i = 0; i < a->argc; i++) {
01005       if (strlen(a->argv[i]) > 100)
01006          ast_cli(a->fd, "Invalid Arguments.\n");
01007    }
01008 
01009    /* Max confno length */
01010    if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01011       return CLI_FAILURE;
01012    }
01013 
01014    if (a->argc == 1 || (a->argc == 2 && !strcasecmp(a->argv[1], "concise"))) {
01015       /* 'MeetMe': List all the conferences */  
01016       int concise = (a->argc == 2 && !strcasecmp(a->argv[1], "concise"));
01017       now = time(NULL);
01018       AST_LIST_LOCK(&confs);
01019       if (AST_LIST_EMPTY(&confs)) {
01020          if (!concise) {
01021             ast_cli(a->fd, "No active MeetMe conferences.\n");
01022          }
01023          AST_LIST_UNLOCK(&confs);
01024          ast_free(cmdline);
01025          return CLI_SUCCESS;
01026       }
01027       if (!concise) {
01028          ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
01029       }
01030       AST_LIST_TRAVERSE(&confs, cnf, list) {
01031          if (cnf->markedusers == 0) {
01032             ast_str_set(&cmdline, 0, "N/A ");
01033          } else {
01034             ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
01035          }
01036          hr = (now - cnf->start) / 3600;
01037          min = ((now - cnf->start) % 3600) / 60;
01038          sec = (now - cnf->start) % 60;
01039          if (!concise) {
01040             ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, cmdline->str, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
01041          } else {
01042             ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
01043                cnf->confno,
01044                cnf->users,
01045                cnf->markedusers,
01046                hr, min, sec,
01047                cnf->isdynamic,
01048                cnf->locked);
01049          }
01050 
01051          total += cnf->users;
01052       }
01053       AST_LIST_UNLOCK(&confs);
01054       if (!concise) {
01055          ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
01056       }
01057       ast_free(cmdline);
01058       return CLI_SUCCESS;
01059    }
01060    if (a->argc < 3) {
01061       ast_free(cmdline);
01062       return CLI_SHOWUSAGE;
01063    }
01064 
01065    ast_str_set(&cmdline, 0, "%s", a->argv[2]);  /* Argv 2: conference number */
01066    if (strstr(a->argv[1], "lock")) {
01067       if (strcmp(a->argv[1], "lock") == 0) {
01068          /* Lock */
01069          ast_str_append(&cmdline, 0, ",L");
01070       } else {
01071          /* Unlock */
01072          ast_str_append(&cmdline, 0, ",l");
01073       }
01074    } else if (strstr(a->argv[1], "mute")) { 
01075       if (a->argc < 4) {
01076          ast_free(cmdline);
01077          return CLI_SHOWUSAGE;
01078       }
01079       if (strcmp(a->argv[1], "mute") == 0) {
01080          /* Mute */
01081          if (strcmp(a->argv[3], "all") == 0) {
01082             ast_str_append(&cmdline, 0, ",N");
01083          } else {
01084             ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);  
01085          }
01086       } else {
01087          /* Unmute */
01088          if (strcmp(a->argv[3], "all") == 0) {
01089             ast_str_append(&cmdline, 0, ",n");
01090          } else {
01091             ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
01092          }
01093       }
01094    } else if (strcmp(a->argv[1], "kick") == 0) {
01095       if (a->argc < 4) {
01096          ast_free(cmdline);
01097          return CLI_SHOWUSAGE;
01098       }
01099       if (strcmp(a->argv[3], "all") == 0) {
01100          /* Kick all */
01101          ast_str_append(&cmdline, 0, ",K");
01102       } else {
01103          /* Kick a single user */
01104          ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
01105       }
01106    } else if (strcmp(a->argv[1], "list") == 0) {
01107       int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
01108       /* List all the users in a conference */
01109       if (AST_LIST_EMPTY(&confs)) {
01110          if (!concise) {
01111             ast_cli(a->fd, "No active conferences.\n");
01112          }
01113          ast_free(cmdline);
01114          return CLI_SUCCESS;  
01115       }
01116       /* Find the right conference */
01117       AST_LIST_LOCK(&confs);
01118       AST_LIST_TRAVERSE(&confs, cnf, list) {
01119          if (strcmp(cnf->confno, a->argv[2]) == 0) {
01120             break;
01121          }
01122       }
01123       if (!cnf) {
01124          if (!concise)
01125             ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
01126          AST_LIST_UNLOCK(&confs);
01127          ast_free(cmdline);
01128          return CLI_SUCCESS;
01129       }
01130       /* Show all the users */
01131       time(&now);
01132       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
01133          hr = (now - user->jointime) / 3600;
01134          min = ((now - user->jointime) % 3600) / 60;
01135          sec = (now - user->jointime) % 60;
01136          if (!concise) {
01137             ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
01138                user->user_no,
01139                S_OR(user->chan->cid.cid_num, "<unknown>"),
01140                S_OR(user->chan->cid.cid_name, "<no name>"),
01141                user->chan->name,
01142                user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
01143                user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
01144                user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
01145                user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
01146                istalking(user->talking), hr, min, sec); 
01147          } else {
01148             ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
01149                user->user_no,
01150                S_OR(user->chan->cid.cid_num, ""),
01151                S_OR(user->chan->cid.cid_name, ""),
01152                user->chan->name,
01153                user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
01154                user->userflags  & CONFFLAG_MONITOR ? "1" : "",
01155                user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
01156                user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
01157                user->talking, hr, min, sec);
01158          }
01159       }
01160       if (!concise) {
01161          ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
01162       }
01163       AST_LIST_UNLOCK(&confs);
01164       ast_free(cmdline);
01165       return CLI_SUCCESS;
01166    } else {
01167       ast_free(cmdline);
01168       return CLI_SHOWUSAGE;
01169    }
01170 
01171    ast_debug(1, "Cmdline: %s\n", cmdline->str);
01172 
01173    admin_exec(NULL, cmdline->str);
01174    ast_free(cmdline);
01175 
01176    return CLI_SUCCESS;
01177 }

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

Definition at line 3641 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, 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, ast_conf_user::list, LOG_NOTICE, ast_conf_user::user_no, and ast_conference::userlist.

Referenced by action_meetmemute(), and action_meetmeunmute().

03642 {
03643    struct ast_conference *conf;
03644    struct ast_conf_user *user;
03645    const char *confid = astman_get_header(m, "Meetme");
03646    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
03647    int userno;
03648 
03649    if (ast_strlen_zero(confid)) {
03650       astman_send_error(s, m, "Meetme conference not specified");
03651       return 0;
03652    }
03653 
03654    if (ast_strlen_zero(userid)) {
03655       astman_send_error(s, m, "Meetme user number not specified");
03656       return 0;
03657    }
03658 
03659    userno = strtoul(userid, &userid, 10);
03660 
03661    if (*userid) {
03662       astman_send_error(s, m, "Invalid user number");
03663       return 0;
03664    }
03665 
03666    /* Look in the conference list */
03667    AST_LIST_LOCK(&confs);
03668    AST_LIST_TRAVERSE(&confs, conf, list) {
03669       if (!strcmp(confid, conf->confno))
03670          break;
03671    }
03672 
03673    if (!conf) {
03674       AST_LIST_UNLOCK(&confs);
03675       astman_send_error(s, m, "Meetme conference does not exist");
03676       return 0;
03677    }
03678 
03679    AST_LIST_TRAVERSE(&conf->userlist, user, list)
03680       if (user->user_no == userno)
03681          break;
03682 
03683    if (!user) {
03684       AST_LIST_UNLOCK(&confs);
03685       astman_send_error(s, m, "User number not found");
03686       return 0;
03687    }
03688 
03689    if (mute)
03690       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
03691    else
03692       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
03693 
03694    AST_LIST_UNLOCK(&confs);
03695 
03696    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);
03697 
03698    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
03699    return 0;
03700 }

static enum ast_device_state meetmestate ( const char *  data  )  [static]

Callback for devicestate providers.

Definition at line 3852 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, ast_conference::list, and ast_conference::users.

Referenced by load_module().

03853 {
03854    struct ast_conference *conf;
03855 
03856    /* Find conference */
03857    AST_LIST_LOCK(&confs);
03858    AST_LIST_TRAVERSE(&confs, conf, list) {
03859       if (!strcmp(data, conf->confno))
03860          break;
03861    }
03862    AST_LIST_UNLOCK(&confs);
03863    if (!conf)
03864       return AST_DEVICE_INVALID;
03865 
03866 
03867    /* SKREP to fill */
03868    if (!conf->users)
03869       return AST_DEVICE_NOT_INUSE;
03870 
03871    return AST_DEVICE_INUSE;
03872 }

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

Definition at line 5191 of file app_meetme.c.

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

Referenced by sla_trunk_exec().

05192 {
05193    struct sla_ringing_trunk *ringing_trunk;
05194 
05195    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
05196       return NULL;
05197    
05198    ringing_trunk->trunk = trunk;
05199    ringing_trunk->ring_begin = ast_tvnow();
05200 
05201    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
05202 
05203    ast_mutex_lock(&sla.lock);
05204    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
05205    ast_mutex_unlock(&sla.lock);
05206 
05207    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05208 
05209    return ringing_trunk;
05210 }

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

Definition at line 3787 of file app_meetme.c.

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

03788 {
03789    struct ast_conference *cnf = args;
03790    struct ast_frame *f = NULL;
03791    int flags;
03792    struct ast_filestream *s = NULL;
03793    int res = 0;
03794    int x;
03795    const char *oldrecordingfilename = NULL;
03796 
03797    if (!cnf || !cnf->lchan) {
03798       pthread_exit(0);
03799    }
03800 
03801    ast_stopstream(cnf->lchan);
03802    flags = O_CREAT | O_TRUNC | O_WRONLY;
03803 
03804 
03805    cnf->recording = MEETME_RECORD_ACTIVE;
03806    while (ast_waitfor(cnf->lchan, -1) > -1) {
03807       if (cnf->recording == MEETME_RECORD_TERMINATE) {
03808          AST_LIST_LOCK(&confs);
03809          AST_LIST_UNLOCK(&confs);
03810          break;
03811       }
03812       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
03813          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
03814          oldrecordingfilename = cnf->recordingfilename;
03815       }
03816       
03817       f = ast_read(cnf->lchan);
03818       if (!f) {
03819          res = -1;
03820          break;
03821       }
03822       if (f->frametype == AST_FRAME_VOICE) {
03823          ast_mutex_lock(&cnf->listenlock);
03824          for (x = 0; x < AST_FRAME_BITS; x++) {
03825             /* Free any translations that have occured */
03826             if (cnf->transframe[x]) {
03827                ast_frfree(cnf->transframe[x]);
03828                cnf->transframe[x] = NULL;
03829             }
03830          }
03831          if (cnf->origframe)
03832             ast_frfree(cnf->origframe);
03833          cnf->origframe = ast_frdup(f);
03834          ast_mutex_unlock(&cnf->listenlock);
03835          if (s)
03836             res = ast_writestream(s, f);
03837          if (res) {
03838             ast_frfree(f);
03839             break;
03840          }
03841       }
03842       ast_frfree(f);
03843    }
03844    cnf->recording = MEETME_RECORD_OFF;
03845    if (s)
03846       ast_closestream(s);
03847    
03848    pthread_exit(0);
03849 }

static int reload ( void   )  [static]

Definition at line 5903 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

05904 {
05905    ast_unload_realtime("meetme");
05906    return load_config(1);
05907 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 772 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

00773 {
00774    signed char zero_volume = 0;
00775 
00776    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00777    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00778 }

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

Definition at line 4090 of file app_meetme.c.

References sla_trunk::active_stations, admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_cond_signal(), ast_dial_destroy(), ast_dial_join(), ast_free, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_str_append(), ast_str_create(), ast_str_set(), build_conf(), sla_trunk_ref::chan, run_station_args::cond, run_station_args::cond_lock, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, sla_station::dial, dispose_conf(), ast_flags::flags, sla_trunk::hold_stations, sla_trunk::name, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, run_station_args::station, ast_str::str, sla_trunk_ref::trunk, and run_station_args::trunk_ref.

Referenced by sla_handle_dial_state_event().

04091 {
04092    struct sla_station *station;
04093    struct sla_trunk_ref *trunk_ref;
04094    struct ast_str *conf_name = ast_str_create(16);
04095    struct ast_flags conf_flags = { 0 };
04096    struct ast_conference *conf;
04097 
04098    {
04099       struct run_station_args *args = data;
04100       station = args->station;
04101       trunk_ref = args->trunk_ref;
04102       ast_mutex_lock(args->cond_lock);
04103       ast_cond_signal(args->cond);
04104       ast_mutex_unlock(args->cond_lock);
04105       /* args is no longer valid here. */
04106    }
04107 
04108    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
04109    ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
04110    ast_set_flag(&conf_flags, 
04111       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04112    answer_trunk_chan(trunk_ref->chan);
04113    conf = build_conf(conf_name->str, "", "", 0, 0, 1, trunk_ref->chan);
04114    if (conf) {
04115       conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
04116       dispose_conf(conf);
04117       conf = NULL;
04118    }
04119    trunk_ref->chan = NULL;
04120    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04121       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04122       ast_str_append(&conf_name, 0, ",K");
04123       admin_exec(NULL, conf_name->str);
04124       trunk_ref->trunk->hold_stations = 0;
04125       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04126    }
04127 
04128    ast_dial_join(station->dial);
04129    ast_dial_destroy(station->dial);
04130    station->dial = NULL;
04131    ast_free(conf_name);
04132 
04133    return NULL;
04134 }

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

Definition at line 701 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

00702 {
00703    char gain_adjust;
00704 
00705    /* attempt to make the adjustment in the channel driver;
00706       if successful, don't adjust in the frame reading routine
00707    */
00708    gain_adjust = gain_map[volume + 5];
00709 
00710    return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00711 }

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

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

00690 {
00691    char gain_adjust;
00692 
00693    /* attempt to make the adjustment in the channel driver;
00694       if successful, don't adjust in the frame reading routine
00695    */
00696    gain_adjust = gain_map[volume + 5];
00697 
00698    return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00699 }

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

Definition at line 5537 of file app_meetme.c.

References ast_atomic_fetchadd_int(), ast_free, AST_LIST_INSERT_TAIL, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdupa, create_trunk_ref(), LOG_ERROR, LOG_WARNING, sla_station::name, sla_trunk::name, sla_trunk::num_stations, sla_trunk_ref::ring_delay, sla_trunk_ref::ring_timeout, sla_create_station_ref(), SLA_TRUNK_STATE_IDLE, sla_trunk_ref::state, sla_trunk::stations, strsep(), sla_station::trunks, and ast_variable::value.

Referenced by sla_build_station().

05538 {
05539    struct sla_trunk *trunk;
05540    struct sla_trunk_ref *trunk_ref;
05541    struct sla_station_ref *station_ref;
05542    char *trunk_name, *options, *cur;
05543 
05544    options = ast_strdupa(var->value);
05545    trunk_name = strsep(&options, ",");
05546    
05547    AST_RWLIST_RDLOCK(&sla_trunks);
05548    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05549       if (!strcasecmp(trunk->name, trunk_name))
05550          break;
05551    }
05552 
05553    AST_RWLIST_UNLOCK(&sla_trunks);
05554    if (!trunk) {
05555       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
05556       return;
05557    }
05558    if (!(trunk_ref = create_trunk_ref(trunk)))
05559       return;
05560    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
05561 
05562    while ((cur = strsep(&options, ","))) {
05563       char *name, *value = cur;
05564       name = strsep(&value, "=");
05565       if (!strcasecmp(name, "ringtimeout")) {
05566          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
05567             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
05568                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05569             trunk_ref->ring_timeout = 0;
05570          }
05571       } else if (!strcasecmp(name, "ringdelay")) {
05572          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
05573             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
05574                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05575             trunk_ref->ring_delay = 0;
05576          }
05577       } else {
05578          ast_log(LOG_WARNING, "Invalid option '%s' for "
05579             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
05580       }
05581    }
05582 
05583    if (!(station_ref = sla_create_station_ref(station))) {
05584       ast_free(trunk_ref);
05585       return;
05586    }
05587    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
05588    AST_RWLIST_WRLOCK(&sla_trunks);
05589    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
05590    AST_RWLIST_UNLOCK(&sla_trunks);
05591    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
05592 }

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

Definition at line 5594 of file app_meetme.c.

References ast_add_extension2(), ast_calloc, ast_context_find_or_create(), ast_free, ast_free_ptr(), AST_LIST_TRAVERSE, ast_log(), AST_MAX_APP, AST_MAX_EXTENSION, AST_RWLIST_INSERT_TAIL, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdup, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_variable_browse(), ast_variable_retrieve(), sla_station::autocontext, context, destroy_station(), exten, sla_station::hold_access, ast_variable::lineno, LOG_ERROR, LOG_WARNING, sla_trunk::name, sla_station::name, ast_variable::name, ast_variable::next, PRIORITY_HINT, sla_station::ring_delay, sla_station::ring_timeout, sla_add_trunk_to_station(), SLA_CONFIG_FILE, SLA_HOLD_OPEN, SLA_HOLD_PRIVATE, sla_registrar, sla_trunk_ref::trunk, sla_station::trunks, ast_variable::value, and var.

Referenced by sla_load_config().

05595 {
05596    struct sla_station *station;
05597    struct ast_variable *var;
05598    const char *dev;
05599 
05600    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05601       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
05602       return -1;
05603    }
05604 
05605    if (!(station = ast_calloc(1, sizeof(*station))))
05606       return -1;
05607    if (ast_string_field_init(station, 32)) {
05608       ast_free(station);
05609       return -1;
05610    }
05611 
05612    ast_string_field_set(station, name, cat);
05613    ast_string_field_set(station, device, dev);
05614 
05615    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05616       if (!strcasecmp(var->name, "trunk"))
05617          sla_add_trunk_to_station(station, var);
05618       else if (!strcasecmp(var->name, "autocontext"))
05619          ast_string_field_set(station, autocontext, var->value);
05620       else if (!strcasecmp(var->name, "ringtimeout")) {
05621          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
05622             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
05623                var->value, station->name);
05624             station->ring_timeout = 0;
05625          }
05626       } else if (!strcasecmp(var->name, "ringdelay")) {
05627          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
05628             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
05629                var->value, station->name);
05630             station->ring_delay = 0;
05631          }
05632       } else if (!strcasecmp(var->name, "hold")) {
05633          if (!strcasecmp(var->value, "private"))
05634             station->hold_access = SLA_HOLD_PRIVATE;
05635          else if (!strcasecmp(var->value, "open"))
05636             station->hold_access = SLA_HOLD_OPEN;
05637          else {
05638             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
05639                var->value, station->name);
05640          }
05641 
05642       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05643          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05644             var->name, var->lineno, SLA_CONFIG_FILE);
05645       }
05646    }
05647 
05648    if (!ast_strlen_zero(station->autocontext)) {
05649       struct ast_context *context;
05650       struct sla_trunk_ref *trunk_ref;
05651       context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
05652       if (!context) {
05653          ast_log(LOG_ERROR, "Failed to automatically find or create "
05654             "context '%s' for SLA!\n", station->autocontext);
05655          destroy_station(station);
05656          return -1;
05657       }
05658       /* The extension for when the handset goes off-hook.
05659        * exten => station1,1,SLAStation(station1) */
05660       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
05661          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
05662          ast_log(LOG_ERROR, "Failed to automatically create extension "
05663             "for trunk '%s'!\n", station->name);
05664          destroy_station(station);
05665          return -1;
05666       }
05667       AST_RWLIST_RDLOCK(&sla_trunks);
05668       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05669          char exten[AST_MAX_EXTENSION];
05670          char hint[AST_MAX_APP];
05671          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05672          snprintf(hint, sizeof(hint), "SLA:%s", exten);
05673          /* Extension for this line button 
05674           * exten => station1_line1,1,SLAStation(station1_line1) */
05675          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
05676             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
05677             ast_log(LOG_ERROR, "Failed to automatically create extension "
05678                "for trunk '%s'!\n", station->name);
05679             destroy_station(station);
05680             return -1;
05681          }
05682          /* Hint for this line button 
05683           * exten => station1_line1,hint,SLA:station1_line1 */
05684          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
05685             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
05686             ast_log(LOG_ERROR, "Failed to automatically create hint "
05687                "for trunk '%s'!\n", station->name);
05688             destroy_station(station);
05689             return -1;
05690          }
05691       }
05692       AST_RWLIST_UNLOCK(&sla_trunks);
05693    }
05694 
05695    AST_RWLIST_WRLOCK(&sla_stations);
05696    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
05697    AST_RWLIST_UNLOCK(&sla_stations);
05698 
05699    return 0;
05700 }

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

Definition at line 5459 of file app_meetme.c.

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

Referenced by sla_load_config().

05460 {
05461    struct sla_trunk *trunk;
05462    struct ast_variable *var;
05463    const char *dev;
05464 
05465    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05466       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
05467       return -1;
05468    }
05469 
05470    if (sla_check_device(dev)) {
05471       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
05472          cat, dev);
05473       return -1;
05474    }
05475 
05476    if (!(trunk = ast_calloc(1, sizeof(*trunk))))
05477       return -1;
05478    if (ast_string_field_init(trunk, 32)) {
05479       ast_free(trunk);
05480       return -1;
05481    }
05482 
05483    ast_string_field_set(trunk, name, cat);
05484    ast_string_field_set(trunk, device, dev);
05485 
05486    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05487       if (!strcasecmp(var->name, "autocontext"))
05488          ast_string_field_set(trunk, autocontext, var->value);
05489       else if (!strcasecmp(var->name, "ringtimeout")) {
05490          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
05491             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
05492                var->value, trunk->name);
05493             trunk->ring_timeout = 0;
05494          }
05495       } else if (!strcasecmp(var->name, "barge"))
05496          trunk->barge_disabled = ast_false(var->value);
05497       else if (!strcasecmp(var->name, "hold")) {
05498          if (!strcasecmp(var->value, "private"))
05499             trunk->hold_access = SLA_HOLD_PRIVATE;
05500          else if (!strcasecmp(var->value, "open"))
05501             trunk->hold_access = SLA_HOLD_OPEN;
05502          else {
05503             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
05504                var->value, trunk->name);
05505          }
05506       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05507          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05508             var->name, var->lineno, SLA_CONFIG_FILE);
05509       }
05510    }
05511 
05512    if (!ast_strlen_zero(trunk->autocontext)) {
05513       struct ast_context *context;
05514       context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
05515       if (!context) {
05516          ast_log(LOG_ERROR, "Failed to automatically find or create "
05517             "context '%s' for SLA!\n", trunk->autocontext);
05518          destroy_trunk(trunk);
05519          return -1;
05520       }
05521       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
05522          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
05523          ast_log(LOG_ERROR, "Failed to automatically create extension "
05524             "for trunk '%s'!\n", trunk->name);
05525          destroy_trunk(trunk);
05526          return -1;
05527       }
05528    }
05529 
05530    AST_RWLIST_WRLOCK(&sla_trunks);
05531    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
05532    AST_RWLIST_UNLOCK(&sla_trunks);
05533 
05534    return 0;
05535 }

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

04704 {
04705    struct sla_station *station;
04706    int res = 0;
04707 
04708    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04709       struct sla_ringing_trunk *ringing_trunk;
04710       int time_left;
04711 
04712       /* Ignore stations already ringing */
04713       if (sla_check_ringing_station(station))
04714          continue;
04715 
04716       /* Ignore stations already on a call */
04717       if (sla_check_inuse_station(station))
04718          continue;
04719 
04720       /* Ignore stations that don't have one of their trunks ringing */
04721       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
04722          continue;
04723 
04724       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
04725          continue;
04726 
04727       /* If there is no time left, then the station needs to start ringing.
04728        * Return non-zero so that an event will be queued up an event to 
04729        * make that happen. */
04730       if (time_left <= 0) {
04731          res = 1;
04732          continue;
04733       }
04734 
04735       if (time_left < *timeout)
04736          *timeout = time_left;
04737    }
04738 
04739    return res;
04740 }

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

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_ringing_station::ring_begin, sla_ringing_trunk::ring_begin, sla_station::ring_timeout, sla_trunk_ref::ring_timeout, sla, SLA_STATION_HANGUP_TIMEOUT, sla_stop_ringing_station(), sla_station_ref::station, sla_ringing_station::station, sla_ringing_trunk::timed_out_stations, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, and sla_station::trunks.

Referenced by sla_process_timers().

04621 {
04622    struct sla_ringing_trunk *ringing_trunk;
04623    struct sla_ringing_station *ringing_station;
04624    int res = 0;
04625 
04626    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04627       unsigned int ring_timeout = 0;
04628       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
04629       struct sla_trunk_ref *trunk_ref;
04630 
04631       /* If there are any ring timeouts specified for a specific trunk
04632        * on the station, then use the highest per-trunk ring timeout.
04633        * Otherwise, use the ring timeout set for the entire station. */
04634       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04635          struct sla_station_ref *station_ref;
04636          int trunk_time_elapsed, trunk_time_left;
04637 
04638          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04639             if (ringing_trunk->trunk == trunk_ref->trunk)
04640                break;
04641          }
04642          if (!ringing_trunk)
04643             continue;
04644 
04645          /* If there is a trunk that is ringing without a timeout, then the
04646           * only timeout that could matter is a global station ring timeout. */
04647          if (!trunk_ref->ring_timeout)
04648             break;
04649 
04650          /* This trunk on this station is ringing and has a timeout.
04651           * However, make sure this trunk isn't still ringing from a
04652           * previous timeout.  If so, don't consider it. */
04653          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
04654             if (station_ref->station == ringing_station->station)
04655                break;
04656          }
04657          if (station_ref)
04658             continue;
04659 
04660          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04661          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
04662          if (trunk_time_left > final_trunk_time_left)
04663             final_trunk_time_left = trunk_time_left;
04664       }
04665 
04666       /* No timeout was found for ringing trunks, and no timeout for the entire station */
04667       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
04668          continue;
04669 
04670       /* Compute how much time is left for a global station timeout */
04671       if (ringing_station->station->ring_timeout) {
04672          ring_timeout = ringing_station->station->ring_timeout;
04673          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
04674          time_left = (ring_timeout * 1000) - time_elapsed;
04675       }
04676 
04677       /* If the time left based on the per-trunk timeouts is smaller than the
04678        * global station ring timeout, use that. */
04679       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
04680          time_left = final_trunk_time_left;
04681 
04682       /* If there is no time left, the station needs to stop ringing */
04683       if (time_left <= 0) {
04684          AST_LIST_REMOVE_CURRENT(entry);
04685          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
04686          res = 1;
04687          continue;
04688       }
04689 
04690       /* There is still some time left for this station to ring, so save that
04691        * timeout if it is the first event scheduled to occur */
04692       if (time_left < *timeout)
04693          *timeout = time_left;
04694    }
04695    AST_LIST_TRAVERSE_SAFE_END;
04696 
04697    return res;
04698 }

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

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_trunk::chan, pbx_builtin_setvar_helper(), sla_ringing_trunk::ring_begin, sla_trunk::ring_timeout, sla, sla_stop_ringing_trunk(), and sla_ringing_trunk::trunk.

Referenced by sla_process_timers().

04591 {
04592    struct sla_ringing_trunk *ringing_trunk;
04593    int res = 0;
04594 
04595    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04596       int time_left, time_elapsed;
04597       if (!ringing_trunk->trunk->ring_timeout)
04598          continue;
04599       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04600       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
04601       if (time_left <= 0) {
04602          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
04603          AST_LIST_REMOVE_CURRENT(entry);
04604          sla_stop_ringing_trunk(ringing_trunk);
04605          res = 1;
04606          continue;
04607       }
04608       if (time_left < *timeout)
04609          *timeout = time_left;
04610    }
04611    AST_LIST_TRAVERSE_SAFE_END;
04612 
04613    return res;
04614 }

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

References ast_devstate_changed(), AST_LIST_TRAVERSE, sla_trunk_ref::chan, sla_trunk::name, sla_station::name, sla_state_to_devstate(), sla_trunk_ref::state, sla_trunk_ref::trunk, and sla_station::trunks.

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

04060 {
04061    struct sla_station *station;
04062    struct sla_trunk_ref *trunk_ref;
04063 
04064    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04065       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04066          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
04067             || trunk_ref == exclude)
04068             continue;
04069          trunk_ref->state = state;
04070          ast_devstate_changed(sla_state_to_devstate(state), 
04071             "SLA:%s_%s", station->name, trunk->name);
04072          break;
04073       }
04074    }
04075 }

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

Definition at line 5446 of file app_meetme.c.

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

Referenced by sla_build_trunk().

05447 {
05448    char *tech, *tech_data;
05449 
05450    tech_data = ast_strdupa(device);
05451    tech = strsep(&tech_data, "/");
05452 
05453    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
05454       return -1;
05455 
05456    return 0;
05457 }

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

References ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tvdiff_ms(), ast_tvnow(), sla_failed_station::last_try, sla, and sla_failed_station::station.

Referenced by sla_ring_stations().

04339 {
04340    struct sla_failed_station *failed_station;
04341    int res = 0;
04342 
04343    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
04344       if (station != failed_station->station)
04345          continue;
04346       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
04347          AST_LIST_REMOVE_CURRENT(entry);
04348          ast_free(failed_station);
04349          break;
04350       }
04351       res = 1;
04352    }
04353    AST_LIST_TRAVERSE_SAFE_END
04354 
04355    return res;
04356 }

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

Check to see if a station is in use.

Definition at line 4424 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla_trunk_ref::chan, and sla_station::trunks.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

04425 {
04426    struct sla_trunk_ref *trunk_ref;
04427 
04428    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04429       if (trunk_ref->chan)
04430          return 1;
04431    }
04432 
04433    return 0;
04434 }

static void sla_check_reload ( void   )  [static]

Check if we can do a reload of SLA, and do it if we can.

Definition at line 4782 of file app_meetme.c.

References AST_LIST_EMPTY, ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, sla_trunk::ref_count, sla_station::ref_count, sla, and sla_load_config().

Referenced by sla_thread().

04783 {
04784    struct sla_station *station;
04785    struct sla_trunk *trunk;
04786 
04787    ast_mutex_lock(&sla.lock);
04788 
04789    if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
04790       || !AST_LIST_EMPTY(&sla.ringing_stations)) {
04791       ast_mutex_unlock(&sla.lock);
04792       return;
04793    }
04794 
04795    AST_RWLIST_RDLOCK(&sla_stations);
04796    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
04797       if (station->ref_count)
04798          break;
04799    }
04800    AST_RWLIST_UNLOCK(&sla_stations);
04801    if (station) {
04802       ast_mutex_unlock(&sla.lock);
04803       return;
04804    }
04805 
04806    AST_RWLIST_RDLOCK(&sla_trunks);
04807    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04808       if (trunk->ref_count)
04809          break;
04810    }
04811    AST_RWLIST_UNLOCK(&sla_trunks);
04812    if (trunk) {
04813       ast_mutex_unlock(&sla.lock);
04814       return;
04815    }
04816 
04817    /* yay */
04818    sla_load_config(1);
04819    sla.reload = 0;
04820 
04821    ast_mutex_unlock(&sla.lock);
04822 }

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

04324 {
04325    struct sla_ringing_station *ringing_station;
04326 
04327    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
04328       if (station == ringing_station->station)
04329          return 1;
04330    }
04331 
04332    return 0;
04333 }

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

References ast_tvdiff_ms(), ast_tvnow(), sla_ringing_trunk::ring_begin, sla_station::ring_delay, sla_trunk_ref::ring_delay, sla_choose_ringing_trunk(), sla_find_trunk_ref(), and sla_ringing_trunk::trunk.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

04456 {
04457    struct sla_trunk_ref *trunk_ref;
04458    unsigned int delay = UINT_MAX;
04459    int time_left, time_elapsed;
04460 
04461    if (!ringing_trunk)
04462       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
04463    else
04464       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
04465 
04466    if (!ringing_trunk || !trunk_ref)
04467       return delay;
04468 
04469    /* If this station has a ring delay specific to the highest priority
04470     * ringing trunk, use that.  Otherwise, use the ring delay specified
04471     * globally for the station. */
04472    delay = trunk_ref->ring_delay;
04473    if (!delay)
04474       delay = station->ring_delay;
04475    if (!delay)
04476       return INT_MAX;
04477 
04478    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04479    time_left = (delay * 1000) - time_elapsed;
04480 
04481    return time_left;
04482 }

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

Definition at line 3963 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla_station::hold_access, SLA_HOLD_PRIVATE, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, sla_station_ref::station, sla_trunk::stations, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_find_trunk_ref_byname().

03965 {
03966    struct sla_station_ref *station_ref;
03967    struct sla_trunk_ref *trunk_ref;
03968 
03969    /* For each station that has this call on hold, check for private hold. */
03970    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03971       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03972          if (trunk_ref->trunk != trunk || station_ref->station == station)
03973             continue;
03974          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03975             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03976             return 1;
03977          return 0;
03978       }
03979    }
03980 
03981    return 0;
03982 }

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

References AST_LIST_TRAVERSE, sla_station_ref::station, and sla_ringing_trunk::timed_out_stations.

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

04196 {
04197    struct sla_station_ref *timed_out_station;
04198 
04199    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
04200       if (station == timed_out_station->station)
04201          return 1;
04202    }
04203 
04204    return 0;
04205 }

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

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

Definition at line 5006 of file app_meetme.c.

References AST_LIST_TRAVERSE, SLA_TRUNK_STATE_IDLE, sla_trunk_ref::state, and sla_station::trunks.

Referenced by sla_station_exec().

05007 {
05008    struct sla_trunk_ref *trunk_ref = NULL;
05009 
05010    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05011       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
05012          break;
05013    }
05014 
05015    return trunk_ref;
05016 }

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

Choose the highest priority ringing trunk for a station.

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

Definition at line 4215 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(), sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_calc_station_delays(), sla_check_station_delay(), and sla_handle_dial_state_event().

04217 {
04218    struct sla_trunk_ref *s_trunk_ref;
04219    struct sla_ringing_trunk *ringing_trunk = NULL;
04220 
04221    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
04222       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04223          /* Make sure this is the trunk we're looking for */
04224          if (s_trunk_ref->trunk != ringing_trunk->trunk)
04225             continue;
04226 
04227          /* This trunk on the station is ringing.  But, make sure this station
04228           * didn't already time out while this trunk was ringing. */
04229          if (sla_check_timed_out_station(ringing_trunk, station))
04230             continue;
04231 
04232          if (rm)
04233             AST_LIST_REMOVE_CURRENT(entry);
04234 
04235          if (trunk_ref)
04236             *trunk_ref = s_trunk_ref;
04237 
04238          break;
04239       }
04240       AST_LIST_TRAVERSE_SAFE_END;
04241    
04242       if (ringing_trunk)
04243          break;
04244    }
04245 
04246    return ringing_trunk;
04247 }

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

Definition at line 4028 of file app_meetme.c.

References ast_calloc, ast_tvnow(), sla_ringing_station::ring_begin, and sla_ringing_station::station.

Referenced by sla_ring_station().

04029 {
04030    struct sla_ringing_station *ringing_station;
04031 
04032    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
04033       return NULL;
04034 
04035    ringing_station->station = station;
04036    ringing_station->ring_begin = ast_tvnow();
04037 
04038    return ringing_station;
04039 }

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

Definition at line 4016 of file app_meetme.c.

References ast_calloc, and sla_station_ref::station.

Referenced by sla_add_trunk_to_station(), and sla_stop_ringing_station().

04017 {
04018    struct sla_station_ref *station_ref;
04019 
04020    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
04021       return NULL;
04022 
04023    station_ref->station = station;
04024 
04025    return station_ref;
04026 }

static void sla_destroy ( void   )  [static]

Definition at line 5416 of file app_meetme.c.

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

Referenced by unload_module().

05417 {
05418    struct sla_trunk *trunk;
05419    struct sla_station *station;
05420 
05421    AST_RWLIST_WRLOCK(&sla_trunks);
05422    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
05423       destroy_trunk(trunk);
05424    AST_RWLIST_UNLOCK(&sla_trunks);
05425 
05426    AST_RWLIST_WRLOCK(&sla_stations);
05427    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
05428       destroy_station(station);
05429    AST_RWLIST_UNLOCK(&sla_stations);
05430 
05431    if (sla.thread != AST_PTHREADT_NULL) {
05432       ast_mutex_lock(&sla.lock);
05433       sla.stop = 1;
05434       ast_cond_signal(&sla.cond);
05435       ast_mutex_unlock(&sla.lock);
05436       pthread_join(sla.thread, NULL);
05437    }
05438 
05439    /* Drop any created contexts from the dialplan */
05440    ast_context_destroy(NULL, sla_registrar);
05441 
05442    ast_mutex_destroy(&sla.lock);
05443    ast_cond_destroy(&sla.cond);
05444 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 4186 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

04187 {
04188    sla_queue_event(SLA_EVENT_DIAL_STATE);
04189 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 3951 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, and sla_station::name.

Referenced by sla_station_exec().

03952 {
03953    struct sla_station *station = NULL;
03954 
03955    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03956       if (!strcasecmp(station->name, name))
03957          break;
03958    }
03959 
03960    return station;
03961 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 3936 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, and sla_trunk::name.

Referenced by sla_trunk_exec().

03937 {
03938    struct sla_trunk *trunk = NULL;
03939 
03940    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03941       if (!strcasecmp(trunk->name, name))
03942          break;
03943    }
03944 
03945    return trunk;
03946 }

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

Definition at line 4436 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_check_station_delay().

04438 {
04439    struct sla_trunk_ref *trunk_ref = NULL;
04440 
04441    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04442       if (trunk_ref->trunk == trunk)
04443          break;
04444    }
04445 
04446    return trunk_ref;
04447 }

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

Find a trunk reference on a station by name.

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

Definition at line 3991 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla_trunk::barge_disabled, sla_trunk::hold_access, sla_trunk::hold_stations, sla_trunk::name, sla_check_station_hold_access(), SLA_HOLD_PRIVATE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_UP, sla_trunk_ref::state, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_station_exec().

03993 {
03994    struct sla_trunk_ref *trunk_ref = NULL;
03995 
03996    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03997       if (strcasecmp(trunk_ref->trunk->name, name))
03998          continue;
03999 
04000       if ( (trunk_ref->trunk->barge_disabled 
04001          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
04002          (trunk_ref->trunk->hold_stations 
04003          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
04004          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
04005          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
04006       {
04007          trunk_ref = NULL;
04008       }
04009 
04010       break;
04011    }
04012 
04013    return trunk_ref;
04014 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 4249 of file app_meetme.c.

References ALL_TRUNK_REFS, answer_trunk_chan(), ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), ast_debug, 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_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_detached_background, sla_trunk::chan, sla_trunk_ref::chan, run_station_args::cond, run_station_args::cond_lock, sla_station::dial, sla_station::name, 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().

04250 {
04251    struct sla_ringing_station *ringing_station;
04252 
04253    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04254       struct sla_trunk_ref *s_trunk_ref = NULL;
04255       struct sla_ringing_trunk *ringing_trunk = NULL;
04256       struct run_station_args args;
04257       enum ast_dial_result dial_res;
04258       pthread_t dont_care;
04259       ast_mutex_t cond_lock;
04260       ast_cond_t cond;
04261 
04262       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
04263       case AST_DIAL_RESULT_HANGUP:
04264       case AST_DIAL_RESULT_INVALID:
04265       case AST_DIAL_RESULT_FAILED:
04266       case AST_DIAL_RESULT_TIMEOUT:
04267       case AST_DIAL_RESULT_UNANSWERED:
04268          AST_LIST_REMOVE_CURRENT(entry);
04269          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
04270          break;
04271       case AST_DIAL_RESULT_ANSWERED:
04272          AST_LIST_REMOVE_CURRENT(entry);
04273          /* Find the appropriate trunk to answer. */
04274          ast_mutex_lock(&sla.lock);
04275          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
04276          ast_mutex_unlock(&sla.lock);
04277          if (!ringing_trunk) {
04278             ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
04279             break;
04280          }
04281          /* Track the channel that answered this trunk */
04282          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
04283          /* Actually answer the trunk */
04284          answer_trunk_chan(ringing_trunk->trunk->chan);
04285          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04286          /* Now, start a thread that will connect this station to the trunk.  The rest of
04287           * the code here sets up the thread and ensures that it is able to save the arguments
04288           * before they are no longer valid since they are allocated on the stack. */
04289          args.trunk_ref = s_trunk_ref;
04290          args.station = ringing_station->station;
04291          args.cond = &cond;
04292          args.cond_lock = &cond_lock;
04293          ast_free(ringing_trunk);
04294          ast_free(ringing_station);
04295          ast_mutex_init(&cond_lock);
04296          ast_cond_init(&cond, NULL);
04297          ast_mutex_lock(&cond_lock);
04298          ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
04299          ast_cond_wait(&cond, &cond_lock);
04300          ast_mutex_unlock(&cond_lock);
04301          ast_mutex_destroy(&cond_lock);
04302          ast_cond_destroy(&cond);
04303          break;
04304       case AST_DIAL_RESULT_TRYING:
04305       case AST_DIAL_RESULT_RINGING:
04306       case AST_DIAL_RESULT_PROGRESS:
04307       case AST_DIAL_RESULT_PROCEEDING:
04308          break;
04309       }
04310       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
04311          /* Queue up reprocessing ringing trunks, and then ringing stations again */
04312          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04313          sla_queue_event(SLA_EVENT_DIAL_STATE);
04314          break;
04315       }
04316    }
04317    AST_LIST_TRAVERSE_SAFE_END;
04318 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 4566 of file app_meetme.c.

References sla_trunk::active_stations, ast_atomic_fetchadd_int(), AST_CAUSE_NORMAL, AST_CONTROL_HOLD, AST_DEVICE_ONHOLD, ast_devstate_changed(), ast_indicate(), ast_softhangup(), sla_trunk_ref::chan, sla_trunk::chan, sla_trunk::hold_stations, INACTIVE_TRUNK_REFS, sla_trunk::name, sla_station::name, sla_change_trunk_state(), SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, sla_event::station, sla_trunk_ref::trunk, and sla_event::trunk_ref.

Referenced by sla_thread().

04567 {
04568    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
04569    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
04570    ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
04571       event->station->name, event->trunk_ref->trunk->name);
04572    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
04573       INACTIVE_TRUNK_REFS, event->trunk_ref);
04574 
04575    if (event->trunk_ref->trunk->active_stations == 1) {
04576       /* The station putting it on hold is the only one on the call, so start
04577        * Music on hold to the trunk. */
04578       event->trunk_ref->trunk->on_hold = 1;
04579       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
04580    }
04581 
04582    ast_softhangup(event->trunk_ref->chan, AST_CAUSE_NORMAL);
04583    event->trunk_ref->chan = NULL;
04584 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 4556 of file app_meetme.c.

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

Referenced by sla_thread().

04557 {
04558    ast_mutex_lock(&sla.lock);
04559    sla_ring_stations();
04560    ast_mutex_unlock(&sla.lock);
04561 
04562    /* Find stations that shouldn't be ringing anymore. */
04563    sla_hangup_stations();
04564 }

static void sla_hangup_stations ( void   )  [static]

Definition at line 4528 of file app_meetme.c.

References ast_dial_destroy(), ast_dial_join(), ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_lock(), ast_mutex_unlock(), sla_station::dial, sla, sla_ringing_station::station, sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_handle_ringing_trunk_event().

04529 {
04530    struct sla_trunk_ref *trunk_ref;
04531    struct sla_ringing_station *ringing_station;
04532 
04533    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04534       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04535          struct sla_ringing_trunk *ringing_trunk;
04536          ast_mutex_lock(&sla.lock);
04537          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04538             if (trunk_ref->trunk == ringing_trunk->trunk)
04539                break;
04540          }
04541          ast_mutex_unlock(&sla.lock);
04542          if (ringing_trunk)
04543             break;
04544       }
04545       if (!trunk_ref) {
04546          AST_LIST_REMOVE_CURRENT(entry);
04547          ast_dial_join(ringing_station->station->dial);
04548          ast_dial_destroy(ringing_station->station->dial);
04549          ringing_station->station->dial = NULL;
04550          ast_free(ringing_station);
04551       }
04552    }
04553    AST_LIST_TRAVERSE_SAFE_END
04554 }

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

Definition at line 1179 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01180 {
01181    const char *hold = "Unknown";
01182 
01183    switch (hold_access) {
01184    case SLA_HOLD_OPEN:
01185       hold = "Open";
01186       break;
01187    case SLA_HOLD_PRIVATE:
01188       hold = "Private";
01189    default:
01190       break;
01191    }
01192 
01193    return hold;
01194 }

static int sla_load_config ( int  reload  )  [static]

Definition at line 5702 of file app_meetme.c.

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

Referenced by load_config(), and sla_check_reload().

05703 {
05704    struct ast_config *cfg;
05705    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
05706    const char *cat = NULL;
05707    int res = 0;
05708    const char *val;
05709 
05710    if (!reload) {
05711       ast_mutex_init(&sla.lock);
05712       ast_cond_init(&sla.cond, NULL);
05713    }
05714 
05715    if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags)))
05716       return 0; /* Treat no config as normal */
05717    else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
05718       return 0;
05719 
05720    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
05721       sla.attempt_callerid = ast_true(val);
05722 
05723    while ((cat = ast_category_browse(cfg, cat)) && !res) {
05724       const char *type;
05725       if (!strcasecmp(cat, "general"))
05726          continue;
05727       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
05728          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
05729             SLA_CONFIG_FILE);
05730          continue;
05731       }
05732       if (!strcasecmp(type, "trunk"))
05733          res = sla_build_trunk(cfg, cat);
05734       else if (!strcasecmp(type, "station"))
05735          res = sla_build_station(cfg, cat);
05736       else {
05737          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
05738             SLA_CONFIG_FILE, type);
05739       }
05740    }
05741 
05742    ast_config_destroy(cfg);
05743 
05744    if (!reload && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations)))
05745       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
05746 
05747    return res;
05748 }

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

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

Referenced by sla_thread().

04745 {
04746    unsigned int timeout = UINT_MAX;
04747    struct timeval wait;
04748    unsigned int change_made = 0;
04749 
04750    /* Check for ring timeouts on ringing trunks */
04751    if (sla_calc_trunk_timeouts(&timeout))
04752       change_made = 1;
04753 
04754    /* Check for ring timeouts on ringing stations */
04755    if (sla_calc_station_timeouts(&timeout))
04756       change_made = 1;
04757 
04758    /* Check for station ring delays */
04759    if (sla_calc_station_delays(&timeout))
04760       change_made = 1;
04761 
04762    /* queue reprocessing of ringing trunks */
04763    if (change_made)
04764       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
04765 
04766    /* No timeout */
04767    if (timeout == UINT_MAX)
04768       return 0;
04769 
04770    if (ts) {
04771       wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
04772       ts->tv_sec = wait.tv_sec;
04773       ts->tv_nsec = wait.tv_usec * 1000;
04774    }
04775 
04776    return 1;
04777 }

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

Queue a SLA event from the conference.

Definition at line 1488 of file app_meetme.c.

References ast_debug, AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strdupa, ast_strlen_zero(), sla_trunk_ref::chan, ast_conference::confno, LOG_ERROR, sla_trunk::name, sla_queue_event_full(), strsep(), sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by conf_run().

01490 {
01491    struct sla_station *station;
01492    struct sla_trunk_ref *trunk_ref = NULL;
01493    char *trunk_name;
01494 
01495    trunk_name = ast_strdupa(conf->confno);
01496    strsep(&trunk_name, "_");
01497    if (ast_strlen_zero(trunk_name)) {
01498       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01499       return;
01500    }
01501 
01502    AST_RWLIST_RDLOCK(&sla_stations);
01503    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01504       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01505          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01506             break;
01507       }
01508       if (trunk_ref)
01509          break;
01510    }
01511    AST_RWLIST_UNLOCK(&sla_stations);
01512 
01513    if (!trunk_ref) {
01514       ast_debug(1, "Trunk not found for event!\n");
01515       return;
01516    }
01517 
01518    sla_queue_event_full(type, trunk_ref, station, 1);
01519 }

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

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

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

01452 {
01453    struct sla_event *event;
01454 
01455    if (sla.thread == AST_PTHREADT_NULL) {
01456       return;
01457    }
01458 
01459    if (!(event = ast_calloc(1, sizeof(*event))))
01460       return;
01461 
01462    event->type = type;
01463    event->trunk_ref = trunk_ref;
01464    event->station = station;
01465 
01466    if (!lock) {
01467       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01468       return;
01469    }
01470 
01471    ast_mutex_lock(&sla.lock);
01472    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01473    ast_cond_signal(&sla.cond);
01474    ast_mutex_unlock(&sla.lock);
01475 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1477 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01478 {
01479    sla_queue_event_full(type, NULL, NULL, 0);
01480 }

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 4361 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_free, AST_LIST_INSERT_HEAD, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvnow(), sla_trunk::chan, ast_channel::cid, ast_callerid::cid_name, cid_name, ast_callerid::cid_num, cid_num, sla_station::device, sla_station::dial, sla_failed_station::last_try, sla, sla_create_ringing_station(), sla_dial_state_callback(), sla_failed_station::station, strsep(), and sla_ringing_trunk::trunk.

Referenced by sla_ring_stations().

04362 {
04363    char *tech, *tech_data;
04364    struct ast_dial *dial;
04365    struct sla_ringing_station *ringing_station;
04366    const char *cid_name = NULL, *cid_num = NULL;
04367    enum ast_dial_result res;
04368 
04369    if (!(dial = ast_dial_create()))
04370       return -1;
04371 
04372    ast_dial_set_state_callback(dial, sla_dial_state_callback);
04373    tech_data = ast_strdupa(station->device);
04374    tech = strsep(&tech_data, "/");
04375 
04376    if (ast_dial_append(dial, tech, tech_data) == -1) {
04377       ast_dial_destroy(dial);
04378       return -1;
04379    }
04380 
04381    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
04382       cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
04383       ast_free(ringing_trunk->trunk->chan->cid.cid_name);
04384       ringing_trunk->trunk->chan->cid.cid_name = NULL;
04385    }
04386    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
04387       cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
04388       ast_free(ringing_trunk->trunk->chan->cid.cid_num);
04389       ringing_trunk->trunk->chan->cid.cid_num = NULL;
04390    }
04391 
04392    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
04393    
04394    if (cid_name)
04395       ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
04396    if (cid_num)
04397       ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
04398    
04399    if (res != AST_DIAL_RESULT_TRYING) {
04400       struct sla_failed_station *failed_station;
04401       ast_dial_destroy(dial);
04402       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
04403          return -1;
04404       failed_station->station = station;
04405       failed_station->last_try = ast_tvnow();
04406       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
04407       return -1;
04408    }
04409    if (!(ringing_station = sla_create_ringing_station(station))) {
04410       ast_dial_join(dial);
04411       ast_dial_destroy(dial);
04412       return -1;
04413    }
04414 
04415    station->dial = dial;
04416 
04417    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
04418 
04419    return 0;
04420 }

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 4487 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(), sla_station_ref::station, sla_trunk::stations, and sla_ringing_trunk::trunk.

Referenced by sla_handle_ringing_trunk_event().

04488 {
04489    struct sla_station_ref *station_ref;
04490    struct sla_ringing_trunk *ringing_trunk;
04491 
04492    /* Make sure that every station that uses at least one of the ringing
04493     * trunks, is ringing. */
04494    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04495       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
04496          int time_left;
04497 
04498          /* Is this station already ringing? */
04499          if (sla_check_ringing_station(station_ref->station))
04500             continue;
04501 
04502          /* Is this station already in a call? */
04503          if (sla_check_inuse_station(station_ref->station))
04504             continue;
04505 
04506          /* Did we fail to dial this station earlier?  If so, has it been
04507           * a minute since we tried? */
04508          if (sla_check_failed_station(station_ref->station))
04509             continue;
04510 
04511          /* If this station already timed out while this trunk was ringing,
04512           * do not dial it again for this ringing trunk. */
04513          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
04514             continue;
04515 
04516          /* Check for a ring delay in progress */
04517          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
04518          if (time_left != INT_MAX && time_left > 0)
04519             continue;
04520 
04521          /* It is time to make this station begin to ring.  Do it! */
04522          sla_ring_station(ringing_trunk, station_ref->station);
04523       }
04524    }
04525    /* Now, all of the stations that should be ringing, are ringing. */
04526 }

static char* sla_show_stations ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1261 of file app_meetme.c.

References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, sla_station::autocontext, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, sla_station::device, ast_cli_args::fd, sla_station::hold_access, sla_trunk::name, sla_station::name, sla_trunk_ref::ring_delay, sla_station::ring_delay, sla_trunk_ref::ring_timeout, sla_station::ring_timeout, S_OR, sla_hold_str(), sla_trunk_ref::state, sla_trunk_ref::trunk, sla_station::trunks, trunkstate2str(), and ast_cli_entry::usage.

01262 {
01263    const struct sla_station *station;
01264 
01265    switch (cmd) {
01266    case CLI_INIT:
01267       e->command = "sla show stations";
01268       e->usage =
01269          "Usage: sla show stations\n"
01270          "       This will list all stations defined in sla.conf\n";
01271       return NULL;
01272    case CLI_GENERATE:
01273       return NULL;
01274    }
01275 
01276    ast_cli(a->fd, "\n" 
01277                "=============================================================\n"
01278                "=== Configured SLA Stations =================================\n"
01279                "=============================================================\n"
01280                "===\n");
01281    AST_RWLIST_RDLOCK(&sla_stations);
01282    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01283       struct sla_trunk_ref *trunk_ref;
01284       char ring_timeout[16] = "(none)";
01285       char ring_delay[16] = "(none)";
01286       if (station->ring_timeout) {
01287          snprintf(ring_timeout, sizeof(ring_timeout), 
01288             "%u", station->ring_timeout);
01289       }
01290       if (station->ring_delay) {
01291          snprintf(ring_delay, sizeof(ring_delay), 
01292             "%u", station->ring_delay);
01293       }
01294       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01295                   "=== Station Name:    %s\n"
01296                   "=== ==> Device:      %s\n"
01297                   "=== ==> AutoContext: %s\n"
01298                   "=== ==> RingTimeout: %s\n"
01299                   "=== ==> RingDelay:   %s\n"
01300                   "=== ==> HoldAccess:  %s\n"
01301                   "=== ==> Trunks ...\n",
01302                   station->name, station->device,
01303                   S_OR(station->autocontext, "(none)"), 
01304                   ring_timeout, ring_delay,
01305                   sla_hold_str(station->hold_access));
01306       AST_RWLIST_RDLOCK(&sla_trunks);
01307       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01308          if (trunk_ref->ring_timeout) {
01309             snprintf(ring_timeout, sizeof(ring_timeout),
01310                "%u", trunk_ref->ring_timeout);
01311          } else
01312             strcpy(ring_timeout, "(none)");
01313          if (trunk_ref->ring_delay) {
01314             snprintf(ring_delay, sizeof(ring_delay),
01315                "%u", trunk_ref->ring_delay);
01316          } else
01317             strcpy(ring_delay, "(none)");
01318             ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
01319                      "===       ==> State:       %s\n"
01320                      "===       ==> RingTimeout: %s\n"
01321                      "===       ==> RingDelay:   %s\n",
01322                      trunk_ref->trunk->name,
01323                      trunkstate2str(trunk_ref->state),
01324                      ring_timeout, ring_delay);
01325       }
01326       AST_RWLIST_UNLOCK(&sla_trunks);
01327       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01328                   "===\n");
01329    }
01330    AST_RWLIST_UNLOCK(&sla_stations);
01331    ast_cli(a->fd, "============================================================\n"
01332                "\n");
01333 
01334    return CLI_SUCCESS;
01335 }

static char* sla_show_trunks ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1196 of file app_meetme.c.

References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, sla_trunk::autocontext, sla_trunk::barge_disabled, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, sla_trunk::device, ast_cli_args::fd, sla_trunk::hold_access, sla_station::name, sla_trunk::name, sla_trunk::ring_timeout, S_OR, sla_hold_str(), sla_station_ref::station, sla_trunk::stations, and ast_cli_entry::usage.

01197 {
01198    const struct sla_trunk *trunk;
01199 
01200    switch (cmd) {
01201    case CLI_INIT:
01202       e->command = "sla show trunks";
01203       e->usage =
01204          "Usage: sla show trunks\n"
01205          "       This will list all trunks defined in sla.conf\n";
01206       return NULL;
01207    case CLI_GENERATE:
01208       return NULL;
01209    }
01210 
01211    ast_cli(a->fd, "\n"
01212                "=============================================================\n"
01213                "=== Configured SLA Trunks ===================================\n"
01214                "=============================================================\n"
01215                "===\n");
01216    AST_RWLIST_RDLOCK(&sla_trunks);
01217    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01218       struct sla_station_ref *station_ref;
01219       char ring_timeout[16] = "(none)";
01220       if (trunk->ring_timeout)
01221          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01222       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01223                   "=== Trunk Name:       %s\n"
01224                   "=== ==> Device:       %s\n"
01225                   "=== ==> AutoContext:  %s\n"
01226                   "=== ==> RingTimeout:  %s\n"
01227                   "=== ==> BargeAllowed: %s\n"
01228                   "=== ==> HoldAccess:   %s\n"
01229                   "=== ==> Stations ...\n",
01230                   trunk->name, trunk->device, 
01231                   S_OR(trunk->autocontext, "(none)"), 
01232                   ring_timeout,
01233                   trunk->barge_disabled ? "No" : "Yes",
01234                   sla_hold_str(trunk->hold_access));
01235       AST_RWLIST_RDLOCK(&sla_stations);
01236       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01237          ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
01238       AST_RWLIST_UNLOCK(&sla_stations);
01239       ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
01240    }
01241    AST_RWLIST_UNLOCK(&sla_trunks);
01242    ast_cli(a->fd, "=============================================================\n\n");
01243 
01244    return CLI_SUCCESS;
01245 }

static enum ast_device_state sla_state ( const char *  data  )  [static]

Definition at line 5340 of file app_meetme.c.

References AST_DEVICE_INVALID, AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_strdupa, buf, LOG_ERROR, sla_trunk::name, sla_station::name, sla_state_to_devstate(), sla_trunk_ref::state, strsep(), sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by load_module().

05341 {
05342    char *buf, *station_name, *trunk_name;
05343    struct sla_station *station;
05344    struct sla_trunk_ref *trunk_ref;
05345    enum ast_device_state res = AST_DEVICE_INVALID;
05346 
05347    trunk_name = buf = ast_strdupa(data);
05348    station_name = strsep(&trunk_name, "_");
05349 
05350    AST_RWLIST_RDLOCK(&sla_stations);
05351    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05352       if (strcasecmp(station_name, station->name))
05353          continue;
05354       AST_RWLIST_RDLOCK(&sla_trunks);
05355       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05356          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
05357             break;
05358       }
05359       if (!trunk_ref) {
05360          AST_RWLIST_UNLOCK(&sla_trunks);
05361          break;
05362       }
05363       res = sla_state_to_devstate(trunk_ref->state);
05364       AST_RWLIST_UNLOCK(&sla_trunks);
05365    }
05366    AST_RWLIST_UNLOCK(&sla_stations);
05367 
05368    if (res == AST_DEVICE_INVALID) {
05369       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
05370          trunk_name, station_name);
05371    }
05372 
05373    return res;
05374 }

static enum ast_device_state sla_state_to_devstate ( enum sla_trunk_state  state  )  [static]
static int sla_station_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 5018 of file app_meetme.c.

References sla_trunk::active_stations, admin_exec(), ALL_TRUNK_REFS, answer_trunk_chan(), ast_answer(), ast_atomic_dec_and_test(), ast_atomic_fetchadd_int(), ast_autoservice_start(), ast_autoservice_stop(), ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), AST_CONTROL_UNHOLD, ast_debug, AST_DEVICE_INUSE, ast_devstate_changed(), ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_detached_background, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, ast_strdupa, ast_strlen_zero(), build_conf(), sla_trunk_ref::chan, sla_trunk::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dial_trunk(), dispose_conf(), ast_flags::flags, free, sla_trunk::hold_stations, LOG_NOTICE, LOG_WARNING, MAX_CONFNUM, sla_trunk::name, sla_station::name, sla_trunk::on_hold, pbx_builtin_setvar_helper(), sla_station::ref_count, sla, sla_change_trunk_state(), sla_choose_idle_trunk(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_find_station(), sla_find_trunk_ref_byname(), sla_queue_event(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, sla_trunk_ref::state, strsep(), sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.

Referenced by load_module().

05019 {
05020    char *station_name, *trunk_name;
05021    struct sla_station *station;
05022    struct sla_trunk_ref *trunk_ref = NULL;
05023    char conf_name[MAX_CONFNUM];
05024    struct ast_flags conf_flags = { 0 };
05025    struct ast_conference *conf;
05026 
05027    if (ast_strlen_zero(data)) {
05028       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05029       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05030       return 0;
05031    }
05032 
05033    trunk_name = ast_strdupa(data);
05034    station_name = strsep(&trunk_name, "_");
05035 
05036    if (ast_strlen_zero(station_name)) {
05037       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05038       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05039       return 0;
05040    }
05041 
05042    AST_RWLIST_RDLOCK(&sla_stations);
05043    station = sla_find_station(station_name);
05044    if (station)
05045       ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
05046    AST_RWLIST_UNLOCK(&sla_stations);
05047 
05048    if (!station) {
05049       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
05050       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05051       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05052       return 0;
05053    }
05054 
05055    AST_RWLIST_RDLOCK(&sla_trunks);
05056    if (!ast_strlen_zero(trunk_name)) {
05057       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
05058    } else
05059       trunk_ref = sla_choose_idle_trunk(station);
05060    AST_RWLIST_UNLOCK(&sla_trunks);
05061 
05062    if (!trunk_ref) {
05063       if (ast_strlen_zero(trunk_name))
05064          ast_log(LOG_NOTICE, "No trunks available for call.\n");
05065       else {
05066          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
05067             "'%s' due to access controls.\n", trunk_name);
05068       }
05069       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05070       ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05071       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05072       return 0;
05073    }
05074 
05075    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
05076       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
05077          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05078       else {
05079          trunk_ref->state = SLA_TRUNK_STATE_UP;
05080          ast_devstate_changed(AST_DEVICE_INUSE, 
05081             "SLA:%s_%s", station->name, trunk_ref->trunk->name);
05082       }
05083    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
05084       struct sla_ringing_trunk *ringing_trunk;
05085 
05086       ast_mutex_lock(&sla.lock);
05087       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05088          if (ringing_trunk->trunk == trunk_ref->trunk) {
05089             AST_LIST_REMOVE_CURRENT(entry);
05090             break;
05091          }
05092       }
05093       AST_LIST_TRAVERSE_SAFE_END
05094       ast_mutex_unlock(&sla.lock);
05095 
05096       if (ringing_trunk) {
05097          answer_trunk_chan(ringing_trunk->trunk->chan);
05098          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05099 
05100          free(ringing_trunk);
05101 
05102          /* Queue up reprocessing ringing trunks, and then ringing stations again */
05103          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05104          sla_queue_event(SLA_EVENT_DIAL_STATE);
05105       }
05106    }
05107 
05108    trunk_ref->chan = chan;
05109 
05110    if (!trunk_ref->trunk->chan) {
05111       ast_mutex_t cond_lock;
05112       ast_cond_t cond;
05113       pthread_t dont_care;
05114       struct dial_trunk_args args = {
05115          .trunk_ref = trunk_ref,
05116          .station = station,
05117          .cond_lock = &cond_lock,
05118          .cond = &cond,
05119       };
05120       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05121       /* Create a thread to dial the trunk and dump it into the conference.
05122        * However, we want to wait until the trunk has been dialed and the
05123        * conference is created before continuing on here. */
05124       ast_autoservice_start(chan);
05125       ast_mutex_init(&cond_lock);
05126       ast_cond_init(&cond, NULL);
05127       ast_mutex_lock(&cond_lock);
05128       ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
05129       ast_cond_wait(&cond, &cond_lock);
05130       ast_mutex_unlock(&cond_lock);
05131       ast_mutex_destroy(&cond_lock);
05132       ast_cond_destroy(&cond);
05133       ast_autoservice_stop(chan);
05134       if (!trunk_ref->trunk->chan) {
05135          ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
05136          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05137          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05138          trunk_ref->chan = NULL;
05139          ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05140          sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05141          return 0;
05142       }
05143    }
05144 
05145    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
05146       trunk_ref->trunk->on_hold) {
05147       trunk_ref->trunk->on_hold = 0;
05148       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
05149       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05150    }
05151 
05152    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05153    ast_set_flag(&conf_flags, 
05154       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05155    ast_answer(chan);
05156    conf = build_conf(conf_name, "", "", 0, 0, 1, chan);
05157    if (conf) {
05158       conf_run(chan, conf, conf_flags.flags, NULL);
05159       dispose_conf(conf);
05160       conf = NULL;
05161    }
05162    trunk_ref->chan = NULL;
05163    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05164       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05165       strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
05166       admin_exec(NULL, conf_name);
05167       trunk_ref->trunk->hold_stations = 0;
05168       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05169    }
05170    
05171    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
05172 
05173    ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05174    sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05175 
05176    return 0;
05177 }

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

Definition at line 4151 of file app_meetme.c.

References ast_dial_destroy(), ast_dial_join(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, sla_station::dial, sla, sla_create_station_ref(), SLA_STATION_HANGUP_NORMAL, sla_ringing_station::station, sla_ringing_trunk::timed_out_stations, sla_trunk_ref::trunk, sla_ringing_trunk::trunk, and sla_station::trunks.

Referenced by sla_calc_station_timeouts(), and sla_handle_dial_state_event().

04153 {
04154    struct sla_ringing_trunk *ringing_trunk;
04155    struct sla_trunk_ref *trunk_ref;
04156    struct sla_station_ref *station_ref;
04157 
04158    ast_dial_join(ringing_station->station->dial);
04159    ast_dial_destroy(ringing_station->station->dial);
04160    ringing_station->station->dial = NULL;
04161 
04162    if (hangup == SLA_STATION_HANGUP_NORMAL)
04163       goto done;
04164 
04165    /* If the station is being hung up because of a timeout, then add it to the
04166     * list of timed out stations on each of the ringing trunks.  This is so
04167     * that when doing further processing to figure out which stations should be
04168     * ringing, which trunk to answer, determining timeouts, etc., we know which
04169     * ringing trunks we should ignore. */
04170    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04171       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04172          if (ringing_trunk->trunk == trunk_ref->trunk)
04173             break;
04174       }
04175       if (!trunk_ref)
04176          continue;
04177       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
04178          continue;
04179       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
04180    }
04181 
04182 done:
04183    ast_free(ringing_station);
04184 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 4136 of file app_meetme.c.

References admin_exec(), ALL_TRUNK_REFS, ast_free, AST_LIST_REMOVE_HEAD, buf, sla_trunk::name, sla_change_trunk_state(), SLA_TRUNK_STATE_IDLE, sla_ringing_trunk::timed_out_stations, and sla_ringing_trunk::trunk.

Referenced by sla_calc_trunk_timeouts().

04137 {
04138    char buf[80];
04139    struct sla_station_ref *station_ref;
04140 
04141    snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
04142    admin_exec(NULL, buf);
04143    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04144 
04145    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
04146       ast_free(station_ref);
04147 
04148    ast_free(ringing_trunk);
04149 }

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

Definition at line 4824 of file app_meetme.c.

References ast_cond_timedwait(), ast_cond_wait(), ast_free, AST_LIST_EMPTY, AST_LIST_REMOVE_HEAD, ast_mutex_lock(), ast_mutex_unlock(), sla, sla_check_reload(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_DIAL_STATE, SLA_EVENT_HOLD, SLA_EVENT_RELOAD, SLA_EVENT_RINGING_TRUNK, sla_handle_dial_state_event(), sla_handle_hold_event(), sla_handle_ringing_trunk_event(), sla_process_timers(), and sla_event::type.

Referenced by sla_load_config().

04825 {
04826    struct sla_failed_station *failed_station;
04827    struct sla_ringing_station *ringing_station;
04828 
04829    ast_mutex_lock(&sla.lock);
04830 
04831    while (!sla.stop) {
04832       struct sla_event *event;
04833       struct timespec ts = { 0, };
04834       unsigned int have_timeout = 0;
04835 
04836       if (AST_LIST_EMPTY(&sla.event_q)) {
04837          if ((have_timeout = sla_process_timers(&ts)))
04838             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
04839          else
04840             ast_cond_wait(&sla.cond, &sla.lock);
04841          if (sla.stop)
04842             break;
04843       }
04844 
04845       if (have_timeout)
04846          sla_process_timers(NULL);
04847 
04848       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
04849          ast_mutex_unlock(&sla.lock);
04850          switch (event->type) {
04851          case SLA_EVENT_HOLD:
04852             sla_handle_hold_event(event);
04853             break;
04854          case SLA_EVENT_DIAL_STATE:
04855             sla_handle_dial_state_event();
04856             break;
04857          case SLA_EVENT_RINGING_TRUNK:
04858             sla_handle_ringing_trunk_event();
04859             break;
04860          case SLA_EVENT_RELOAD:
04861             sla.reload = 1;
04862          case SLA_EVENT_CHECK_RELOAD:
04863             break;
04864          }
04865          ast_free(event);
04866          ast_mutex_lock(&sla.lock);
04867       }
04868 
04869       if (sla.reload)
04870          sla_check_reload();
04871    }
04872 
04873    ast_mutex_unlock(&sla.lock);
04874 
04875    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
04876       ast_free(ringing_station);
04877 
04878    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
04879       ast_free(failed_station);
04880 
04881    return NULL;
04882 }

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

Definition at line 5225 of file app_meetme.c.

References ALL_TRUNK_REFS, AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_free, 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, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, build_conf(), sla_trunk::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, dispose_conf(), ast_flags::flags, LOG_ERROR, MAX_CONFNUM, sla_trunk::on_hold, OPT_ARG_ARRAY_SIZE, OPT_ARG_MOH_CLASS, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), queue_ringing_trunk(), sla_trunk::ref_count, sla, sla_change_trunk_state(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), SLA_TRUNK_OPT_ARG_ARRAY_SIZE, SLA_TRUNK_OPT_ARG_MOH_CLASS, SLA_TRUNK_OPT_MOH, sla_trunk_opts, SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by load_module().

05226 {
05227    char conf_name[MAX_CONFNUM];
05228    struct ast_conference *conf;
05229    struct ast_flags conf_flags = { 0 };
05230    struct sla_trunk *trunk;
05231    struct sla_ringing_trunk *ringing_trunk;
05232    AST_DECLARE_APP_ARGS(args,
05233       AST_APP_ARG(trunk_name);
05234       AST_APP_ARG(options);
05235    );
05236    char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
05237    char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
05238    struct ast_flags opt_flags = { 0 };
05239    char *parse;
05240 
05241    if (ast_strlen_zero(data)) {
05242       ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
05243       return -1;
05244    }
05245 
05246    parse = ast_strdupa(data);
05247    AST_STANDARD_APP_ARGS(args, parse);
05248    if (args.argc == 2) {
05249       if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
05250          ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
05251          return -1;
05252       }
05253    }
05254 
05255    AST_RWLIST_RDLOCK(&sla_trunks);
05256    trunk = sla_find_trunk(args.trunk_name);
05257    if (trunk)
05258       ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
05259    AST_RWLIST_UNLOCK(&sla_trunks);
05260 
05261    if (!trunk) {
05262       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
05263       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05264       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05265       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05266       return 0;
05267    }
05268 
05269    if (trunk->chan) {
05270       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
05271          args.trunk_name);
05272       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05273       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05274       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05275       return 0;
05276    }
05277 
05278    trunk->chan = chan;
05279 
05280    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
05281       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05282       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05283       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05284       return 0;
05285    }
05286 
05287    snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
05288    conf = build_conf(conf_name, "", "", 1, 1, 1, chan);
05289    if (!conf) {
05290       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05291       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05292       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05293       return 0;
05294    }
05295    ast_set_flag(&conf_flags, 
05296       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
05297 
05298    if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
05299       ast_indicate(chan, -1);
05300       ast_set_flag(&conf_flags, CONFFLAG_MOH);
05301       conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
05302    } else
05303       ast_indicate(chan, AST_CONTROL_RINGING);
05304 
05305    conf_run(chan, conf, conf_flags.flags, opts);
05306    dispose_conf(conf);
05307    conf = NULL;
05308    trunk->chan = NULL;
05309    trunk->on_hold = 0;
05310 
05311    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05312 
05313    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
05314       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
05315 
05316    /* Remove the entry from the list of ringing trunks if it is still there. */
05317    ast_mutex_lock(&sla.lock);
05318    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05319       if (ringing_trunk->trunk == trunk) {
05320          AST_LIST_REMOVE_CURRENT(entry);
05321          break;
05322       }
05323    }
05324    AST_LIST_TRAVERSE_SAFE_END;
05325    ast_mutex_unlock(&sla.lock);
05326    if (ringing_trunk) {
05327       ast_free(ringing_trunk);
05328       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
05329       /* Queue reprocessing of ringing trunks to make stations stop ringing
05330        * that shouldn't be ringing after this trunk stopped. */
05331       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05332    }
05333 
05334    ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05335    sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05336 
05337    return 0;
05338 }

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

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

01248 {
01249 #define S(e) case e: return # e;
01250    switch (state) {
01251    S(SLA_TRUNK_STATE_IDLE)
01252    S(SLA_TRUNK_STATE_RINGING)
01253    S(SLA_TRUNK_STATE_UP)
01254    S(SLA_TRUNK_STATE_ONHOLD)
01255    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01256    }
01257    return "Uknown State";
01258 #undef S
01259 }

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

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

00761 {
00762    tweak_volume(&user->listen, action);
00763    /* attempt to make the adjustment in the channel driver;
00764       if successful, don't adjust in the frame reading routine
00765    */
00766    if (!set_listen_volume(user, user->listen.desired))
00767       user->listen.actual = 0;
00768    else
00769       user->listen.actual = user->listen.desired;
00770 }

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

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

00749 {
00750    tweak_volume(&user->talk, action);
00751    /* attempt to make the adjustment in the channel driver;
00752       if successful, don't adjust in the frame reading routine
00753    */
00754    if (!set_talk_volume(user, user->talk.desired))
00755       user->talk.actual = 0;
00756    else
00757       user->talk.actual = user->talk.desired;
00758 }

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

Definition at line 713 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

00714 {
00715    switch (action) {
00716    case VOL_UP:
00717       switch (vol->desired) { 
00718       case 5:
00719          break;
00720       case 0:
00721          vol->desired = 2;
00722          break;
00723       case -2:
00724          vol->desired = 0;
00725          break;
00726       default:
00727          vol->desired++;
00728          break;
00729       }
00730       break;
00731    case VOL_DOWN:
00732       switch (vol->desired) {
00733       case -5:
00734          break;
00735       case 2:
00736          vol->desired = 0;
00737          break;
00738       case 0:
00739          vol->desired = -2;
00740          break;
00741       default:
00742          vol->desired--;
00743          break;
00744       }
00745    }
00746 }

static int unload_module ( void   )  [static]

Definition at line 5846 of file app_meetme.c.

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

05847 {
05848    int res = 0;
05849    
05850    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05851    res = ast_manager_unregister("MeetmeMute");
05852    res |= ast_manager_unregister("MeetmeUnmute");
05853    res |= ast_manager_unregister("MeetmeList");
05854    res |= ast_unregister_application(app4);
05855    res |= ast_unregister_application(app3);
05856    res |= ast_unregister_application(app2);
05857    res |= ast_unregister_application(app);
05858    res |= ast_unregister_application(slastation_app);
05859    res |= ast_unregister_application(slatrunk_app);
05860 
05861    ast_devstate_prov_del("Meetme");
05862    ast_devstate_prov_del("SLA");
05863    
05864    sla_destroy();
05865    
05866    res |= ast_custom_function_unregister(&meetme_info_acf);
05867    ast_unload_realtime("meetme");
05868 
05869    return res;
05870 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "MeetMe conference bridge" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 5913 of file app_meetme.c.

const char* app = "MeetMe" [static]

Definition at line 209 of file app_meetme.c.

const char* app2 = "MeetMeCount" [static]

Definition at line 210 of file app_meetme.c.

const char* app3 = "MeetMeAdmin" [static]

Definition at line 211 of file app_meetme.c.

const char* app4 = "MeetMeChannelAdmin" [static]

Definition at line 212 of file app_meetme.c.

Definition at line 5913 of file app_meetme.c.

unsigned int attempt_callerid

Attempt to handle CallerID, even though it is known not to work properly in some situations.

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

struct ast_cli_entry cli_meetme[] [static]
Initial value:
 {
   AST_CLI_DEFINE(meetme_cmd, "Execute a command on a conference or conferee"),
   AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
   AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
}

Definition at line 1337 of file app_meetme.c.

Definition at line 608 of file app_meetme.c.

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

Definition at line 419 of file app_meetme.c.

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

const char* descrip [static]

Definition at line 232 of file app_meetme.c.

const char* descrip2 [static]

Definition at line 295 of file app_meetme.c.

const char* descrip3 [static]

Definition at line 303 of file app_meetme.c.

const char* descrip4 [static]

Definition at line 326 of file app_meetme.c.

int earlyalert [static]

Definition at line 226 of file app_meetme.c.

int endalert [static]

Definition at line 227 of file app_meetme.c.

struct { ... } event_q
struct { ... } failed_stations
struct sla_event* first [read]
int fuzzystart [static]

Definition at line 225 of file app_meetme.c.

char const gain_map[] [static]

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

Definition at line 634 of file app_meetme.c.

struct sla_event* last [read]

Definition at line 609 of file app_meetme.c.

char mandescr_meetmelist[] [static]

Definition at line 3712 of file app_meetme.c.

Definition at line 5817 of file app_meetme.c.

struct ast_app_option meetme_opts[128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, } [static]

Definition at line 207 of file app_meetme.c.

Referenced by conf_exec().

static int reload

A reload has been requested

reload: Part of Asterisk module interface ---

Definition at line 619 of file app_meetme.c.

Referenced by handle_cli_moh_reload(), handle_minivm_reload(), reload(), rpt_do_reload(), and show_console().

struct { ... } ringing_stations
struct { ... } ringing_trunks
int rt_log_members [static]

Definition at line 230 of file app_meetme.c.

int rt_schedule [static]

Definition at line 224 of file app_meetme.c.

struct { ... } sla [static]
const char sla_registrar[] = "SLA" [static]
struct ast_app_option sla_trunk_opts[128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, } [static]

Definition at line 5223 of file app_meetme.c.

Referenced by sla_trunk_exec().

const char* slastation_app = "SLAStation" [static]

Definition at line 213 of file app_meetme.c.

const char* slastation_desc [static]

Definition at line 334 of file app_meetme.c.

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

Definition at line 220 of file app_meetme.c.

const char* slatrunk_app = "SLATrunk" [static]

Definition at line 214 of file app_meetme.c.

const char* slatrunk_desc [static]

Definition at line 347 of file app_meetme.c.

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

Definition at line 221 of file app_meetme.c.

unsigned int stop

Definition at line 614 of file app_meetme.c.

Referenced by controlplayback_exec(), handle_controlstreamfile(), and queue_exec().

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

Definition at line 216 of file app_meetme.c.

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

Definition at line 217 of file app_meetme.c.

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

Definition at line 218 of file app_meetme.c.

const char* synopsis4 = "MeetMe conference Administration (channel specific)" [static]

Definition at line 219 of file app_meetme.c.

pthread_t thread

The SLA thread ID

Definition at line 607 of file app_meetme.c.


Generated on 3 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1