Fri Jul 24 00:41:09 2009

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"

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 {
      sla_event *   first
      sla_event *   last
   }   event_q
   struct {
      sla_failed_station *   first
      sla_failed_station *   last
   }   failed_stations
   ast_mutex_t   lock
   unsigned int   reload:1
   struct {
      sla_ringing_station *   first
      sla_ringing_station *   last
   }   ringing_stations
   struct {
      sla_ringing_trunk *   first
      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_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 5202 of file app_meetme.c.

05202      {
05203    SLA_TRUNK_OPT_MOH = (1 << 0),
05204 };

anonymous enum

Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 5206 of file app_meetme.c.

05206      {
05207    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
05208    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
05209 };

enum announcetypes

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 362 of file app_meetme.c.

00362                    {
00363    CONF_HASJOIN,
00364    CONF_HASLEFT
00365 };

enum entrance_sound

Enumerator:
ENTER 
LEAVE 

Definition at line 93 of file app_meetme.c.

00093                     {
00094    ENTER,
00095    LEAVE
00096 };

enum recording_state

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 98 of file app_meetme.c.

enum sla_event_type

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

Enumerator:
SLA_EVENT_HOLD  A station has put the call on hold
SLA_EVENT_DIAL_STATE  The state of a dial has changed
SLA_EVENT_RINGING_TRUNK  The state of a ringing trunk has changed
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 };

enum sla_hold_access

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

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

enum sla_station_hangup

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 589 of file app_meetme.c.

enum sla_trunk_state

Enumerator:
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 454 of file app_meetme.c.

enum sla_which_trunk_refs

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

enum volume_action

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

static void __unreg_module ( void   )  [static]

Definition at line 5903 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 5758 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, and parse().

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

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

Definition at line 5740 of file app_meetme.c.

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

Referenced by acf_meetme_info().

05741 {
05742    if (!strcasecmp("lock", keyword)) {
05743       return conf->locked;
05744    } else if (!strcasecmp("parties", keyword)) {
05745       return conf->users;
05746    } else if (!strcasecmp("activity", keyword)) {
05747       time_t now;
05748       now = time(NULL);
05749       return (now - conf->start);
05750    } else if (!strcasecmp("dynamic", keyword)) {
05751       return conf->isdynamic;
05752    } else {
05753       return -1;
05754    }
05755 
05756 }

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

Definition at line 3710 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, 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(), CONFFLAG_ADMIN, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_conference::confno, ast_conf_user::list, s, S_OR, total, user, and ast_conference::userlist.

Referenced by load_module().

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

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

Definition at line 3692 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03693 {
03694    return meetmemute(s, m, 1);
03695 }

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

Definition at line 3697 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03698 {
03699    return meetmemute(s, m, 0);
03700 }

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

The MeetMeadmin application.

Definition at line 3422 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, 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(), user, ast_conference::userlist, and VOL_UP.

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

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

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(), announce_listitem::confchan, announce_listitem::confusers, announce_listitem::entry, 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 4074 of file app_meetme.c.

References ast_answer(), ast_indicate(), and chan.

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

04075 {
04076    ast_answer(chan);
04077    ast_indicate(chan, -1);
04078 }

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

Find or create a conference.

Parameters:
confno The conference name/number
pin The regular user pin
pinadmin The admin pin
make Make the conf if it doesn't exist
dynamic Mark the newly created conference as dynamic
refcount How many references to mark on the conference
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_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, chan, conf_map, ast_conference::confno, LOG_WARNING, and ast_channel::uniqueid.

Referenced by 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, "%d", &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, chan, 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.

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

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, 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::list, LOG_NOTICE, LOG_WARNING, user, and ast_conference::userlist.

Referenced by load_module().

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

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 3158 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(), chan, 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, OPT_ARG_ARRAY_SIZE, ast_conference::pin, ast_conference::pinadmin, strsep(), and var.

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

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(), chan, 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, ao2_ref, ast_cond_signal(), ast_filedelete(), AST_FRAME_BITS, ast_frfree, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_translator_free_path(), ast_conference::chan, ast_conference::confno, announce_listitem::entry, EVENT_FLAG_CALL, manager_event, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, announce_listitem::namerecloc, 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(), chan, enter, ENTER, ast_conference::fd, 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(), f, ast_conf_user::list, LOG_WARNING, user, 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 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, 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_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_conf_user::chan, ast_conference::chan, chan, conf_flush(), CONF_HASJOIN, conf_play(), conf_queue_dtmf(), CONF_SIZE, conf_start_moh(), 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, ast_conference::dahdiconf, dtmfstr, ast_conference::endalert, ast_conference::endtime, ENTER, announce_listitem::entry, errno, EVENT_FLAG_CALL, exitcontext, f, ast_channel::fds, ast_frame::frametype, ast_channel::language, ast_conference::lchan, ast_conference::listenlock, ast_conference::locked, LOG_WARNING, manager_event, ast_conference::markedusers, ast_conference::maxusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, ast_channel::monitor, ast_channel::name, 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_conference::playlock, 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, sec, set_talk_volume(), SLA_EVENT_HOLD, sla_queue_event_conf(), strsep(), ast_channel::tech, THRESHOLD_SILENCE, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_conference::uniqueid, ast_channel::uniqueid, user, ast_conf_user::userflags, ast_conference::userlist, ast_conference::users, var, and VOL_UP.

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], "%d", &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) && !(confflags & CONFFLAG_MONITOR) && !(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) && !(confflags & CONFFLAG_MONITOR)) {
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                         if (can_write(chan, confflags) && ast_write(chan, conf->transframe[idx]))
02758                            ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02759                      }
02760                   } else {
02761                      ast_mutex_unlock(&conf->listenlock);
02762                      goto bailoutandtrynormal;
02763                   }
02764                   ast_mutex_unlock(&conf->listenlock);
02765                } else {
02766 bailoutandtrynormal:             
02767                   if (user->listen.actual)
02768                      ast_frame_adjust_volume(&fr, user->listen.actual);
02769                   if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
02770                      ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02771                   }
02772                }
02773             } else 
02774                ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
02775          }
02776          lastmarked = currentmarked;
02777       }
02778    }
02779 
02780    if (musiconhold)
02781       ast_moh_stop(chan);
02782    
02783    if (using_pseudo)
02784       close(fd);
02785    else {
02786       /* Take out of conference */
02787       dahdic.chan = 0;  
02788       dahdic.confno = 0;
02789       dahdic.confmode = 0;
02790       if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02791          ast_log(LOG_WARNING, "Error setting conference\n");
02792       }
02793    }
02794 
02795    reset_volumes(user);
02796 
02797    if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
02798       conf_play(chan, conf, LEAVE);
02799 
02800    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02801       struct announce_listitem *item;
02802       if (!(item = ao2_alloc(sizeof(*item), NULL)))
02803          return -1;
02804       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02805       ast_copy_string(item->language, chan->language, sizeof(item->language));
02806       item->confchan = conf->chan;
02807       item->confusers = conf->users;
02808       item->announcetype = CONF_HASLEFT;
02809       ast_mutex_lock(&conf->announcelistlock);
02810       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02811       ast_cond_signal(&conf->announcelist_addition);
02812       ast_mutex_unlock(&conf->announcelistlock);
02813    } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) {
02814       /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
02815       ast_filedelete(user->namerecloc, NULL);
02816    }
02817 
02818  outrun:
02819    AST_LIST_LOCK(&confs);
02820 
02821    if (dsp)
02822       ast_dsp_free(dsp);
02823    
02824    if (user->user_no) { /* Only cleanup users who really joined! */
02825       now = ast_tvnow();
02826       hr = (now.tv_sec - user->jointime) / 3600;
02827       min = ((now.tv_sec - user->jointime) % 3600) / 60;
02828       sec = (now.tv_sec - user->jointime) % 60;
02829 
02830       if (sent_event) {
02831          manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
02832                   "Channel: %s\r\n"
02833                   "Uniqueid: %s\r\n"
02834                   "Meetme: %s\r\n"
02835                   "Usernum: %d\r\n"
02836                   "CallerIDNum: %s\r\n"
02837                   "CallerIDName: %s\r\n"
02838                   "Duration: %ld\r\n",
02839                   chan->name, chan->uniqueid, conf->confno, 
02840                   user->user_no,
02841                   S_OR(user->chan->cid.cid_num, "<unknown>"),
02842                   S_OR(user->chan->cid.cid_name, "<unknown>"),
02843                   (long)(now.tv_sec - user->jointime));
02844       }
02845 
02846       if (setusercount) {
02847          conf->users--;
02848          if (rt_log_members) {
02849             /* Update table */
02850             snprintf(members, sizeof(members), "%d", conf->users);
02851             ast_realtime_require_field("meetme",
02852                "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
02853                "members", RQ_UINTEGER1, strlen(members),
02854                NULL);
02855             ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
02856          }
02857          if (confflags & CONFFLAG_MARKEDUSER) 
02858             conf->markedusers--;
02859       }
02860       /* Remove ourselves from the list */
02861       AST_LIST_REMOVE(&conf->userlist, user, list);
02862 
02863       /* Change any states */
02864       if (!conf->users)
02865          ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
02866       
02867       /* Return the number of seconds the user was in the conf */
02868       snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
02869       pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
02870    }
02871    ast_free(user);
02872    AST_LIST_UNLOCK(&confs);
02873 
02874    return ret;
02875 }

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, ast_string_field_set, chan, and ast_channel::musicclass.

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 3113 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(), chan, dispose_conf(), find_conf(), LOG_WARNING, pbx_builtin_setvar_helper(), and ast_conference::users.

Referenced by load_module().

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

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

Definition at line 5169 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

05170 {
05171    struct sla_trunk_ref *trunk_ref;
05172 
05173    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
05174       return NULL;
05175 
05176    trunk_ref->trunk = trunk;
05177 
05178    return trunk_ref;
05179 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 5380 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, announce_listitem::entry, exten, sla_trunk::name, sla_station::name, PRIORITY_HINT, sla_registrar, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_destroy().

05381 {
05382    struct sla_trunk_ref *trunk_ref;
05383 
05384    if (!ast_strlen_zero(station->autocontext)) {
05385       AST_RWLIST_RDLOCK(&sla_trunks);
05386       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05387          char exten[AST_MAX_EXTENSION];
05388          char hint[AST_MAX_APP];
05389          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05390          snprintf(hint, sizeof(hint), "SLA:%s", exten);
05391          ast_context_remove_extension(station->autocontext, exten, 
05392             1, sla_registrar);
05393          ast_context_remove_extension(station->autocontext, hint, 
05394             PRIORITY_HINT, sla_registrar);
05395       }
05396       AST_RWLIST_UNLOCK(&sla_trunks);
05397    }
05398 
05399    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
05400       ast_free(trunk_ref);
05401 
05402    ast_string_field_free_memory(station);
05403    ast_free(station);
05404 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 5366 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, announce_listitem::entry, sla_registrar, and sla_trunk::stations.

Referenced by sla_destroy().

05367 {
05368    struct sla_station_ref *station_ref;
05369 
05370    if (!ast_strlen_zero(trunk->autocontext))
05371       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
05372 
05373    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
05374       ast_free(station_ref);
05375 
05376    ast_string_field_free_memory(trunk);
05377    ast_free(trunk);
05378 }

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

Definition at line 4881 of file app_meetme.c.

References ast_cond_signal(), ast_dial_answered(), ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_run(), ast_dial_state(), ast_free, ast_mutex_lock(), ast_mutex_unlock(), ast_strdup, ast_strdupa, ast_strlen_zero(), 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, sla_trunk::device, MAX_CONFNUM, sla, strsep(), sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.

Referenced by sla_station_exec().

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

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(), 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, "%d", &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]

Definition at line 3015 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, chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFIG_FILE_NAME, config_flags, ast_conference::confno, ast_conference::list, LOG_WARNING, parse(), ast_conference::refcount, S_OR, and var.

Referenced by conf_exec(), and count_exec().

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

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]

Definition at line 2877 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, chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, ast_conference::confno, DATE_FORMAT, ast_conference::endalert, ast_conference::endtime, ast_channel::language, ast_conference::list, LOG_WARNING, ast_conference::maxusers, ast_conference::refcount, and var.

Referenced by conf_exec().

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

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

Definition at line 3405 of file app_meetme.c.

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

03406 {
03407    struct ast_conf_user *user = NULL;
03408    int cid;
03409    
03410    sscanf(callerident, "%i", &cid);
03411    if (conf && callerident) {
03412       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03413          if (cid == user->user_no)
03414             return user;
03415       }
03416    }
03417    return NULL;
03418 }

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

Definition at line 1556 of file app_meetme.c.

References CONF_HASJOIN.

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.

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

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

05823 {
05824    load_config_meetme();
05825 
05826    if (reload) {
05827       sla_queue_event(SLA_EVENT_RELOAD);
05828       ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
05829          "and will be completed when the system is idle.\n");
05830       return 0;
05831    }
05832    
05833    return sla_load_config(0);
05834 }

static void load_config_meetme ( void   )  [static]

Definition at line 3864 of file app_meetme.c.

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

Referenced by load_config().

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

static int load_module ( void   )  [static]

Definition at line 5862 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(), cli_meetme, conf_exec(), count_exec(), EVENT_FLAG_CALL, EVENT_FLAG_REPORTING, load_config(), meetme_info_acf, meetmestate(), RQ_UINTEGER1, RQ_UINTEGER2, sla_state(), sla_station_exec(), and sla_trunk_exec().

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

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 ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_free, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_str_create(), ast_str_set(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd(), ast_conference::confno, ast_cli_args::fd, ast_conference::isdynamic, 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, sec, ast_conference::start, ast_str::str, total, ast_cli_entry::usage, 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 3631 of file app_meetme.c.

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

Referenced by action_meetmemute(), and action_meetmeunmute().

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

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

Callback for devicestate providers.

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

03843 {
03844    struct ast_conference *conf;
03845 
03846    /* Find conference */
03847    AST_LIST_LOCK(&confs);
03848    AST_LIST_TRAVERSE(&confs, conf, list) {
03849       if (!strcmp(data, conf->confno))
03850          break;
03851    }
03852    AST_LIST_UNLOCK(&confs);
03853    if (!conf)
03854       return AST_DEVICE_INVALID;
03855 
03856 
03857    /* SKREP to fill */
03858    if (!conf->users)
03859       return AST_DEVICE_NOT_INUSE;
03860 
03861    return AST_DEVICE_INUSE;
03862 }

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

Definition at line 5181 of file app_meetme.c.

References ALL_TRUNK_REFS, ast_calloc, AST_LIST_INSERT_HEAD, ast_mutex_lock(), ast_mutex_unlock(), ast_tvnow(), announce_listitem::entry, 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().

05182 {
05183    struct sla_ringing_trunk *ringing_trunk;
05184 
05185    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
05186       return NULL;
05187    
05188    ringing_trunk->trunk = trunk;
05189    ringing_trunk->ring_begin = ast_tvnow();
05190 
05191    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
05192 
05193    ast_mutex_lock(&sla.lock);
05194    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
05195    ast_mutex_unlock(&sla.lock);
05196 
05197    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05198 
05199    return ringing_trunk;
05200 }

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

Definition at line 3777 of file app_meetme.c.

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

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

static int reload ( void   )  [static]

Definition at line 5893 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

05894 {
05895    ast_unload_realtime("meetme");
05896    return load_config(1);
05897 }

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 user.

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

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

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 user.

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 user.

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 5527 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(), announce_listitem::entry, 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_station_ref::station, sla_trunk::stations, strsep(), sla_station::trunks, and var.

Referenced by sla_build_station().

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

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

Definition at line 5584 of file app_meetme.c.

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

Referenced by sla_load_config().

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

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

Definition at line 5449 of file app_meetme.c.

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

Referenced by sla_load_config().

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

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

References AST_LIST_TRAVERSE, announce_listitem::entry, sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), and sla_choose_ringing_trunk().

Referenced by sla_process_timers().

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

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 4610 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(), announce_listitem::entry, 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().

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

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 4580 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, announce_listitem::entry, 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().

04581 {
04582    struct sla_ringing_trunk *ringing_trunk;
04583    int res = 0;
04584 
04585    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04586       int time_left, time_elapsed;
04587       if (!ringing_trunk->trunk->ring_timeout)
04588          continue;
04589       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04590       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
04591       if (time_left <= 0) {
04592          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
04593          AST_LIST_REMOVE_CURRENT(entry);
04594          sla_stop_ringing_trunk(ringing_trunk);
04595          res = 1;
04596          continue;
04597       }
04598       if (time_left < *timeout)
04599          *timeout = time_left;
04600    }
04601    AST_LIST_TRAVERSE_SAFE_END;
04602 
04603    return res;
04604 }

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

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

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

04050 {
04051    struct sla_station *station;
04052    struct sla_trunk_ref *trunk_ref;
04053 
04054    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04055       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04056          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
04057             || trunk_ref == exclude)
04058             continue;
04059          trunk_ref->state = state;
04060          ast_devstate_changed(sla_state_to_devstate(state), 
04061             "SLA:%s_%s", station->name, trunk->name);
04062          break;
04063       }
04064    }
04065 }

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

Definition at line 5436 of file app_meetme.c.

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

Referenced by sla_build_trunk().

05437 {
05438    char *tech, *tech_data;
05439 
05440    tech_data = ast_strdupa(device);
05441    tech = strsep(&tech_data, "/");
05442 
05443    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
05444       return -1;
05445 
05446    return 0;
05447 }

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 4328 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(), announce_listitem::entry, sla_failed_station::last_try, sla, and sla_failed_station::station.

Referenced by sla_ring_stations().

04329 {
04330    struct sla_failed_station *failed_station;
04331    int res = 0;
04332 
04333    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
04334       if (station != failed_station->station)
04335          continue;
04336       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
04337          AST_LIST_REMOVE_CURRENT(entry);
04338          ast_free(failed_station);
04339          break;
04340       }
04341       res = 1;
04342    }
04343    AST_LIST_TRAVERSE_SAFE_END
04344 
04345    return res;
04346 }

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

Check to see if a station is in use.

Definition at line 4414 of file app_meetme.c.

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

Referenced by sla_calc_station_delays(), and sla_ring_stations().

04415 {
04416    struct sla_trunk_ref *trunk_ref;
04417 
04418    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04419       if (trunk_ref->chan)
04420          return 1;
04421    }
04422 
04423    return 0;
04424 }

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

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

Referenced by sla_thread().

04773 {
04774    struct sla_station *station;
04775    struct sla_trunk *trunk;
04776 
04777    ast_mutex_lock(&sla.lock);
04778 
04779    if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
04780       || !AST_LIST_EMPTY(&sla.ringing_stations)) {
04781       ast_mutex_unlock(&sla.lock);
04782       return;
04783    }
04784 
04785    AST_RWLIST_RDLOCK(&sla_stations);
04786    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
04787       if (station->ref_count)
04788          break;
04789    }
04790    AST_RWLIST_UNLOCK(&sla_stations);
04791    if (station) {
04792       ast_mutex_unlock(&sla.lock);
04793       return;
04794    }
04795 
04796    AST_RWLIST_RDLOCK(&sla_trunks);
04797    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04798       if (trunk->ref_count)
04799          break;
04800    }
04801    AST_RWLIST_UNLOCK(&sla_trunks);
04802    if (trunk) {
04803       ast_mutex_unlock(&sla.lock);
04804       return;
04805    }
04806 
04807    /* yay */
04808    sla_load_config(1);
04809    sla.reload = 0;
04810 
04811    ast_mutex_unlock(&sla.lock);
04812 }

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

References AST_LIST_TRAVERSE, announce_listitem::entry, sla, and sla_ringing_station::station.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

04314 {
04315    struct sla_ringing_station *ringing_station;
04316 
04317    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
04318       if (station == ringing_station->station)
04319          return 1;
04320    }
04321 
04322    return 0;
04323 }

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

04446 {
04447    struct sla_trunk_ref *trunk_ref;
04448    unsigned int delay = UINT_MAX;
04449    int time_left, time_elapsed;
04450 
04451    if (!ringing_trunk)
04452       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
04453    else
04454       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
04455 
04456    if (!ringing_trunk || !trunk_ref)
04457       return delay;
04458 
04459    /* If this station has a ring delay specific to the highest priority
04460     * ringing trunk, use that.  Otherwise, use the ring delay specified
04461     * globally for the station. */
04462    delay = trunk_ref->ring_delay;
04463    if (!delay)
04464       delay = station->ring_delay;
04465    if (!delay)
04466       return INT_MAX;
04467 
04468    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04469    time_left = (delay * 1000) - time_elapsed;
04470 
04471    return time_left;
04472 }

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

Definition at line 3953 of file app_meetme.c.

References AST_LIST_TRAVERSE, announce_listitem::entry, 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().

03955 {
03956    struct sla_station_ref *station_ref;
03957    struct sla_trunk_ref *trunk_ref;
03958 
03959    /* For each station that has this call on hold, check for private hold. */
03960    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03961       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03962          if (trunk_ref->trunk != trunk || station_ref->station == station)
03963             continue;
03964          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03965             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03966             return 1;
03967          return 0;
03968       }
03969    }
03970 
03971    return 0;
03972 }

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

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

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

04186 {
04187    struct sla_station_ref *timed_out_station;
04188 
04189    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
04190       if (station == timed_out_station->station)
04191          return 1;
04192    }
04193 
04194    return 0;
04195 }

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

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

Definition at line 4996 of file app_meetme.c.

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

Referenced by sla_station_exec().

04997 {
04998    struct sla_trunk_ref *trunk_ref = NULL;
04999 
05000    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05001       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
05002          break;
05003    }
05004 
05005    return trunk_ref;
05006 }

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

Choose the highest priority ringing trunk for a station.

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

Definition at line 4205 of file app_meetme.c.

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, announce_listitem::entry, 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().

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

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

Definition at line 4018 of file app_meetme.c.

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

Referenced by sla_ring_station().

04019 {
04020    struct sla_ringing_station *ringing_station;
04021 
04022    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
04023       return NULL;
04024 
04025    ringing_station->station = station;
04026    ringing_station->ring_begin = ast_tvnow();
04027 
04028    return ringing_station;
04029 }

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

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

04007 {
04008    struct sla_station_ref *station_ref;
04009 
04010    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
04011       return NULL;
04012 
04013    station_ref->station = station;
04014 
04015    return station_ref;
04016 }

static void sla_destroy ( void   )  [static]

Definition at line 5406 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(), announce_listitem::entry, sla, and sla_registrar.

Referenced by unload_module().

05407 {
05408    struct sla_trunk *trunk;
05409    struct sla_station *station;
05410 
05411    AST_RWLIST_WRLOCK(&sla_trunks);
05412    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
05413       destroy_trunk(trunk);
05414    AST_RWLIST_UNLOCK(&sla_trunks);
05415 
05416    AST_RWLIST_WRLOCK(&sla_stations);
05417    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
05418       destroy_station(station);
05419    AST_RWLIST_UNLOCK(&sla_stations);
05420 
05421    if (sla.thread != AST_PTHREADT_NULL) {
05422       ast_mutex_lock(&sla.lock);
05423       sla.stop = 1;
05424       ast_cond_signal(&sla.cond);
05425       ast_mutex_unlock(&sla.lock);
05426       pthread_join(sla.thread, NULL);
05427    }
05428 
05429    /* Drop any created contexts from the dialplan */
05430    ast_context_destroy(NULL, sla_registrar);
05431 
05432    ast_mutex_destroy(&sla.lock);
05433    ast_cond_destroy(&sla.cond);
05434 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 4176 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

04177 {
04178    sla_queue_event(SLA_EVENT_DIAL_STATE);
04179 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 3941 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, announce_listitem::entry, and sla_station::name.

Referenced by sla_station_exec().

03942 {
03943    struct sla_station *station = NULL;
03944 
03945    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03946       if (!strcasecmp(station->name, name))
03947          break;
03948    }
03949 
03950    return station;
03951 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 3926 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, announce_listitem::entry, and sla_trunk::name.

Referenced by sla_trunk_exec().

03927 {
03928    struct sla_trunk *trunk = NULL;
03929 
03930    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03931       if (!strcasecmp(trunk->name, name))
03932          break;
03933    }
03934 
03935    return trunk;
03936 }

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

Definition at line 4426 of file app_meetme.c.

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

Referenced by sla_check_station_delay().

04428 {
04429    struct sla_trunk_ref *trunk_ref = NULL;
04430 
04431    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04432       if (trunk_ref->trunk == trunk)
04433          break;
04434    }
04435 
04436    return trunk_ref;
04437 }

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

Find a trunk reference on a station by name.

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

Definition at line 3981 of file app_meetme.c.

References AST_LIST_TRAVERSE, sla_trunk::barge_disabled, announce_listitem::entry, 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().

03983 {
03984    struct sla_trunk_ref *trunk_ref = NULL;
03985 
03986    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03987       if (strcasecmp(trunk_ref->trunk->name, name))
03988          continue;
03989 
03990       if ( (trunk_ref->trunk->barge_disabled 
03991          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
03992          (trunk_ref->trunk->hold_stations 
03993          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
03994          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
03995          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
03996       {
03997          trunk_ref = NULL;
03998       }
03999 
04000       break;
04001    }
04002 
04003    return trunk_ref;
04004 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 4239 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, announce_listitem::entry, 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().

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

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 4556 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_trunk::on_hold, sla_change_trunk_state(), SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, sla_event::station, sla_trunk_ref::trunk, and sla_event::trunk_ref.

Referenced by sla_thread().

04557 {
04558    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
04559    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
04560    ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
04561       event->station->name, event->trunk_ref->trunk->name);
04562    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
04563       INACTIVE_TRUNK_REFS, event->trunk_ref);
04564 
04565    if (event->trunk_ref->trunk->active_stations == 1) {
04566       /* The station putting it on hold is the only one on the call, so start
04567        * Music on hold to the trunk. */
04568       event->trunk_ref->trunk->on_hold = 1;
04569       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
04570    }
04571 
04572    ast_softhangup(event->trunk_ref->chan, AST_CAUSE_NORMAL);
04573    event->trunk_ref->chan = NULL;
04574 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 4546 of file app_meetme.c.

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

Referenced by sla_thread().

04547 {
04548    ast_mutex_lock(&sla.lock);
04549    sla_ring_stations();
04550    ast_mutex_unlock(&sla.lock);
04551 
04552    /* Find stations that shouldn't be ringing anymore. */
04553    sla_hangup_stations();
04554 }

static void sla_hangup_stations ( void   )  [static]

Definition at line 4518 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, announce_listitem::entry, sla, sla_ringing_station::station, sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by sla_handle_ringing_trunk_event().

04519 {
04520    struct sla_trunk_ref *trunk_ref;
04521    struct sla_ringing_station *ringing_station;
04522 
04523    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04524       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04525          struct sla_ringing_trunk *ringing_trunk;
04526          ast_mutex_lock(&sla.lock);
04527          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04528             if (trunk_ref->trunk == ringing_trunk->trunk)
04529                break;
04530          }
04531          ast_mutex_unlock(&sla.lock);
04532          if (ringing_trunk)
04533             break;
04534       }
04535       if (!trunk_ref) {
04536          AST_LIST_REMOVE_CURRENT(entry);
04537          ast_dial_join(ringing_station->station->dial);
04538          ast_dial_destroy(ringing_station->station->dial);
04539          ringing_station->station->dial = NULL;
04540          ast_free(ringing_station);
04541       }
04542    }
04543    AST_LIST_TRAVERSE_SAFE_END
04544 }

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 5692 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_flags, 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().

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

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

04735 {
04736    unsigned int timeout = UINT_MAX;
04737    struct timeval wait;
04738    unsigned int change_made = 0;
04739 
04740    /* Check for ring timeouts on ringing trunks */
04741    if (sla_calc_trunk_timeouts(&timeout))
04742       change_made = 1;
04743 
04744    /* Check for ring timeouts on ringing stations */
04745    if (sla_calc_station_timeouts(&timeout))
04746       change_made = 1;
04747 
04748    /* Check for station ring delays */
04749    if (sla_calc_station_delays(&timeout))
04750       change_made = 1;
04751 
04752    /* queue reprocessing of ringing trunks */
04753    if (change_made)
04754       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
04755 
04756    /* No timeout */
04757    if (timeout == UINT_MAX)
04758       return 0;
04759 
04760    if (ts) {
04761       wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
04762       ts->tv_sec = wait.tv_sec;
04763       ts->tv_nsec = wait.tv_usec * 1000;
04764    }
04765 
04766    return 1;
04767 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

Definition at line 1482 of file app_meetme.c.

References sla_queue_event_full().

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

01483 {
01484    sla_queue_event_full(type, NULL, NULL, 1);
01485 }

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(), chan, sla_trunk_ref::chan, ast_conference::confno, announce_listitem::entry, 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, announce_listitem::entry, sla, sla_event::station, and sla_event::trunk_ref.

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 4351 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, announce_listitem::entry, sla, sla_create_ringing_station(), sla_dial_state_callback(), sla_failed_station::station, sla_ringing_station::station, strsep(), and sla_ringing_trunk::trunk.

Referenced by sla_ring_stations().

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

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

References AST_LIST_TRAVERSE, announce_listitem::entry, 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().

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

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, announce_listitem::entry, 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, announce_listitem::entry, 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 5330 of file app_meetme.c.

References AST_DEVICE_INVALID, ast_device_state(), AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_strdupa, buf, announce_listitem::entry, 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().

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

static enum ast_device_state sla_state_to_devstate ( enum sla_trunk_state  state  )  [static]

Definition at line 4031 of file app_meetme.c.

References AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_UNKNOWN, 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_change_trunk_state(), and sla_state().

04032 {
04033    switch (state) {
04034    case SLA_TRUNK_STATE_IDLE:
04035       return AST_DEVICE_NOT_INUSE;
04036    case SLA_TRUNK_STATE_RINGING:
04037       return AST_DEVICE_RINGING;
04038    case SLA_TRUNK_STATE_UP:
04039       return AST_DEVICE_INUSE;
04040    case SLA_TRUNK_STATE_ONHOLD:
04041    case SLA_TRUNK_STATE_ONHOLD_BYME:
04042       return AST_DEVICE_ONHOLD;
04043    }
04044 
04045    return AST_DEVICE_UNKNOWN;
04046 }

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

Definition at line 5008 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, chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dial_trunk(), dispose_conf(), announce_listitem::entry, 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, dial_trunk_args::station, strsep(), sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.

Referenced by load_module().

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

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

Definition at line 4141 of file app_meetme.c.

References ast_dial_destroy(), ast_dial_join(), ast_free, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, sla_station::dial, announce_listitem::entry, 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().

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

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 4126 of file app_meetme.c.

References admin_exec(), ALL_TRUNK_REFS, ast_free, AST_LIST_REMOVE_HEAD, buf, announce_listitem::entry, 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().

04127 {
04128    char buf[80];
04129    struct sla_station_ref *station_ref;
04130 
04131    snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
04132    admin_exec(NULL, buf);
04133    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04134 
04135    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
04136       ast_free(station_ref);
04137 
04138    ast_free(ringing_trunk);
04139 }

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

Definition at line 4814 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(), announce_listitem::entry, 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().

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

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

Definition at line 5215 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, chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, dispose_conf(), announce_listitem::entry, 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().

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

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 set_listen_volume(), tweak_volume(), and user.

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 set_talk_volume(), tweak_volume(), and user.

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, 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 5836 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(), cli_meetme, meetme_info_acf, and sla_destroy().

05837 {
05838    int res = 0;
05839    
05840    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05841    res = ast_manager_unregister("MeetmeMute");
05842    res |= ast_manager_unregister("MeetmeUnmute");
05843    res |= ast_manager_unregister("MeetmeList");
05844    res |= ast_unregister_application(app4);
05845    res |= ast_unregister_application(app3);
05846    res |= ast_unregister_application(app2);
05847    res |= ast_unregister_application(app);
05848    res |= ast_unregister_application(slastation_app);
05849    res |= ast_unregister_application(slatrunk_app);
05850 
05851    ast_devstate_prov_del("Meetme");
05852    ast_devstate_prov_del("SLA");
05853    
05854    sla_destroy();
05855    
05856    res |= ast_custom_function_unregister(&meetme_info_acf);
05857    ast_unload_realtime("meetme");
05858 
05859    return res;
05860 }


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 5903 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.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 5903 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:

 {
   { .handler =  meetme_cmd , .summary =  "Execute a command on a conference or conferee" ,__VA_ARGS__ },
   { .handler =  sla_show_trunks , .summary =  "Show SLA Trunks" ,__VA_ARGS__ },
   { .handler =  sla_show_stations , .summary =  "Show SLA Stations" ,__VA_ARGS__ },
}

Definition at line 1337 of file app_meetme.c.

Referenced by load_module(), and unload_module().

ast_cond_t cond

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

Definition at line 613 of file app_meetme.c.

struct sla_failed_station* first

Definition at line 612 of file app_meetme.c.

struct sla_ringing_station* first

Definition at line 611 of file app_meetme.c.

struct sla_ringing_trunk* first

Definition at line 610 of file app_meetme.c.

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

Definition at line 613 of file app_meetme.c.

struct sla_failed_station* last

Definition at line 612 of file app_meetme.c.

struct sla_ringing_station* last

Definition at line 611 of file app_meetme.c.

struct sla_ringing_trunk* last

Definition at line 610 of file app_meetme.c.

ast_mutex_t lock

Definition at line 609 of file app_meetme.c.

char mandescr_meetmelist[] [static]

Definition at line 3702 of file app_meetme.c.

struct ast_custom_function meetme_info_acf [static]

Definition at line 5807 of file app_meetme.c.

Referenced by load_module(), and unload_module().

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

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]

A structure for data used by the sla thread.

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

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

Definition at line 549 of file app_meetme.c.

Referenced by destroy_station(), destroy_trunk(), and sla_destroy().

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 5213 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 Fri Jul 24 00:41:10 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7