Fri Nov 12 11:50:04 2010

Asterisk developer's documentation


app_meetme.c File Reference

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

#include "asterisk.h"
#include <dahdi/user.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/astobj2.h"
#include "asterisk/devicestate.h"
#include "asterisk/dial.h"
#include "asterisk/causes.h"
#include "asterisk/paths.h"
#include "enter.h"
#include "leave.h"
Include dependency graph for app_meetme.c:

Go to the source code of this file.

Data Structures

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

Defines

#define AST_FRAME_BITS   32
#define CONF_SIZE   320
#define CONFIG_FILE_NAME   "meetme.conf"
#define DATE_FORMAT   "%Y-%m-%d %H:%M:%S"
#define DEFAULT_AUDIO_BUFFERS   32
#define MAX_CONFNUM   80
#define MAX_PIN   80
#define MAX_SETTINGS   (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)
#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 OPTIONS_LEN   100
#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, 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 char * meetme_show_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 int rt_extend_conf (char *confno)
static void * run_station (void *data)
static void send_talking_event (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
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 set_user_talking (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
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 = "0901e4e500243c855563a2d78b0c03e4" , .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 int earlyalert
static int endalert
static int extendby
static int fuzzystart
static char const gain_map []
static char mandescr_meetmelist []
static struct ast_custom_function meetme_info_acf
static struct ast_app_option meetme_opts [128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
static int rt_log_members
static int rt_schedule
struct {
   unsigned int   attempt_callerid:1
   ast_cond_t   cond
   struct {
      struct sla_event *   first
      struct sla_event *   last
   }   event_q
   struct {
      struct sla_failed_station *   first
      struct sla_failed_station *   last
   }   failed_stations
   ast_mutex_t   lock
   unsigned int   reload:1
   struct {
      struct sla_ringing_station *   first
      struct sla_ringing_station *   last
   }   ringing_stations
   struct {
      struct sla_ringing_trunk *   first
      struct sla_ringing_trunk *   last
   }   ringing_trunks
   unsigned int   stop:1
   pthread_t   thread
sla
 A structure for data used by the sla thread.
static const char sla_registrar [] = "SLA"
static struct ast_app_option sla_trunk_opts [128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, }
static const char * slastation_app = "SLAStation"
static const char * slatrunk_app = "SLATrunk"

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

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

#define CONF_SIZE   320

Definition at line 464 of file app_meetme.c.

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 425 of file app_meetme.c.

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

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

String format for scheduled conferences

Definition at line 432 of file app_meetme.c.

Referenced by append_date(), build_radius_record(), conf_run(), execute_cb(), find_conf_realtime(), format_date(), get_date(), manager_log(), pgsql_log(), and rt_extend_conf().

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 429 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80
#define MAX_PIN   80

Definition at line 586 of file app_meetme.c.

Referenced by conf_exec().

#define MAX_SETTINGS   (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)

Definition at line 590 of file app_meetme.c.

Referenced by conf_exec(), and find_conf().

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

Referenced by meetme_show_cmd().

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

Referenced by meetme_show_cmd().

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 443 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 442 of file app_meetme.c.

Referenced by conf_run().

#define OPTIONS_LEN   100

Definition at line 587 of file app_meetme.c.

Referenced by find_conf_realtime().

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

Referenced by sms_readfile(), and trunkstate2str().

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 426 of file app_meetme.c.

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


Enumeration Type Documentation

anonymous enum
Enumerator:
ADMINFLAG_MUTED 

User is muted

ADMINFLAG_SELFMUTED 

User muted self

ADMINFLAG_KICKME 

User has been kicked

ADMINFLAG_T_REQUEST 

User has requested to speak

Definition at line 434 of file app_meetme.c.

00434      {
00435    ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
00436    ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
00437    ADMINFLAG_KICKME =    (1 << 3),  /*!< User has been kicked */
00438    /*! User has requested to speak */
00439    ADMINFLAG_T_REQUEST = (1 << 4),
00440 };

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

00466      {
00467    /*! user has admin access on the conference */
00468    CONFFLAG_ADMIN = (1 << 0),
00469    /*! If set the user can only receive audio from the conference */
00470    CONFFLAG_MONITOR = (1 << 1),
00471    /*! If set asterisk will exit conference when key defined in p() option is pressed */
00472    CONFFLAG_KEYEXIT = (1 << 2),
00473    /*! If set asterisk will provide a menu to the user when '*' is pressed */
00474    CONFFLAG_STARMENU = (1 << 3),
00475    /*! If set the use can only send audio to the conference */
00476    CONFFLAG_TALKER = (1 << 4),
00477    /*! If set there will be no enter or leave sounds */
00478    CONFFLAG_QUIET = (1 << 5),
00479    /*! If set, when user joins the conference, they will be told the number 
00480     *  of users that are already in */
00481    CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
00482    /*! Set to run AGI Script in Background */
00483    CONFFLAG_AGI = (1 << 7),
00484    /*! Set to have music on hold when user is alone in conference */
00485    CONFFLAG_MOH = (1 << 8),
00486    /*! If set the MeetMe will return if all marked with this flag left */
00487    CONFFLAG_MARKEDEXIT = (1 << 9),
00488    /*! If set, the MeetMe will wait until a marked user enters */
00489    CONFFLAG_WAITMARKED = (1 << 10),
00490    /*! If set, the MeetMe will exit to the specified context */
00491    CONFFLAG_EXIT_CONTEXT = (1 << 11),
00492    /*! If set, the user will be marked */
00493    CONFFLAG_MARKEDUSER = (1 << 12),
00494    /*! If set, user will be ask record name on entry of conference */
00495    CONFFLAG_INTROUSER = (1 << 13),
00496    /*! If set, the MeetMe will be recorded */
00497    CONFFLAG_RECORDCONF = (1<< 14),
00498    /*! If set, the user will be monitored if the user is talking or not */
00499    CONFFLAG_MONITORTALKER = (1 << 15),
00500    CONFFLAG_DYNAMIC = (1 << 16),
00501    CONFFLAG_DYNAMICPIN = (1 << 17),
00502    CONFFLAG_EMPTY = (1 << 18),
00503    CONFFLAG_EMPTYNOPIN = (1 << 19),
00504    CONFFLAG_ALWAYSPROMPT = (1 << 20),
00505    /*! If set, treat talking users as muted users */
00506    CONFFLAG_OPTIMIZETALKER = (1 << 21),
00507    /*! If set, won't speak the extra prompt when the first person 
00508     *  enters the conference */
00509    CONFFLAG_NOONLYPERSON = (1 << 22),
00510    /*! If set, user will be asked to record name on entry of conference 
00511     *  without review */
00512    CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
00513    /*! If set, the user will be initially self-muted */
00514    CONFFLAG_STARTMUTED = (1 << 24),
00515    /*! Pass DTMF through the conference */
00516    CONFFLAG_PASS_DTMF = (1 << 25),
00517    CONFFLAG_SLA_STATION = (1 << 26),
00518    CONFFLAG_SLA_TRUNK = (1 << 27),
00519    /*! If set, the user should continue in the dialplan if kicked out */
00520    CONFFLAG_KICK_CONTINUE = (1 << 28),
00521    CONFFLAG_DURATION_STOP = (1 << 29),
00522    CONFFLAG_DURATION_LIMIT = (1 << 30),
00523    /*! Do not write any audio to this channel until the state is up. */
00524    CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31),
00525 };

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

00527      {
00528    OPT_ARG_WAITMARKED = 0,
00529    OPT_ARG_EXITKEYS   = 1,
00530    OPT_ARG_DURATION_STOP = 2,
00531    OPT_ARG_DURATION_LIMIT = 3,
00532    OPT_ARG_MOH_CLASS = 4,
00533    OPT_ARG_ARRAY_SIZE = 5,
00534 };

anonymous enum
Enumerator:
SLA_TRUNK_OPT_MOH 

Definition at line 5795 of file app_meetme.c.

05795      {
05796    SLA_TRUNK_OPT_MOH = (1 << 0),
05797 };

anonymous enum
Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 5799 of file app_meetme.c.

05799      {
05800    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
05801    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
05802 };

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 592 of file app_meetme.c.

00592                    {
00593    CONF_HASJOIN,
00594    CONF_HASLEFT
00595 };

Enumerator:
ENTER 
LEAVE 

Definition at line 452 of file app_meetme.c.

00452                     {
00453    ENTER,
00454    LEAVE
00455 };

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 457 of file app_meetme.c.

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

Enumerator:
SLA_EVENT_HOLD 

A station has put the call on hold

SLA_EVENT_DIAL_STATE 

The state of a dial has changed

SLA_EVENT_RINGING_TRUNK 

The state of a ringing trunk has changed

SLA_EVENT_RELOAD 

A reload of configuration has been requested

SLA_EVENT_CHECK_RELOAD 

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

Definition at line 785 of file app_meetme.c.

00785                     {
00786    /*! A station has put the call on hold */
00787    SLA_EVENT_HOLD,
00788    /*! The state of a dial has changed */
00789    SLA_EVENT_DIAL_STATE,
00790    /*! The state of a ringing trunk has changed */
00791    SLA_EVENT_RINGING_TRUNK,
00792    /*! A reload of configuration has been requested */
00793    SLA_EVENT_RELOAD,
00794    /*! Poke the SLA thread so it can check if it can perform a reload */
00795    SLA_EVENT_CHECK_RELOAD,
00796 };

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

00695                      {
00696    /*! This means that any station can put it on hold, and any station
00697     * can retrieve the call from hold. */
00698    SLA_HOLD_OPEN,
00699    /*! This means that only the station that put the call on hold may
00700     * retrieve it from hold. */
00701    SLA_HOLD_PRIVATE,
00702 };

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 822 of file app_meetme.c.

Enumerator:
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 687 of file app_meetme.c.

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 682 of file app_meetme.c.

00682                           {
00683    ALL_TRUNK_REFS,
00684    INACTIVE_TRUNK_REFS,
00685 };

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 447 of file app_meetme.c.

00447                    {
00448    VOL_UP,
00449    VOL_DOWN
00450 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 6500 of file app_meetme.c.

static void __unreg_module ( void   )  [static]

Definition at line 6500 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 6355 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_strlen_zero(), ast_conference::confno, ast_conference::list, LOG_ERROR, LOG_NOTICE, and parse().

06356 {
06357    struct ast_conference *conf;
06358    char *parse;
06359    int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
06360    AST_DECLARE_APP_ARGS(args,
06361       AST_APP_ARG(keyword);
06362       AST_APP_ARG(confno);
06363    );
06364 
06365    if (ast_strlen_zero(data)) {
06366       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
06367       return -1;
06368    }
06369 
06370    parse = ast_strdupa(data);
06371    AST_STANDARD_APP_ARGS(args, parse);
06372 
06373    if (ast_strlen_zero(args.keyword)) {
06374       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
06375       return -1;
06376    }
06377 
06378    if (ast_strlen_zero(args.confno)) {
06379       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
06380       return -1;
06381    }
06382 
06383    AST_LIST_LOCK(&confs);
06384    AST_LIST_TRAVERSE(&confs, conf, list) {
06385       if (!strcmp(args.confno, conf->confno)) {
06386          result = acf_meetme_info_eval(args.keyword, conf);
06387          break;
06388       }
06389    }
06390    AST_LIST_UNLOCK(&confs);
06391 
06392    if (result > -1) {
06393       snprintf(buf, len, "%d", result);
06394    } else if (result == -1) {
06395       ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
06396       snprintf(buf, len, "0");
06397    } else if (result == -2) {
06398       ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno); 
06399       snprintf(buf, len, "0");
06400    }
06401 
06402    return 0;
06403 }

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

Definition at line 6337 of file app_meetme.c.

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

Referenced by acf_meetme_info().

06338 {
06339    if (!strcasecmp("lock", keyword)) {
06340       return conf->locked;
06341    } else if (!strcasecmp("parties", keyword)) {
06342       return conf->users;
06343    } else if (!strcasecmp("activity", keyword)) {
06344       time_t now;
06345       now = time(NULL);
06346       return (now - conf->start);
06347    } else if (!strcasecmp("dynamic", keyword)) {
06348       return conf->isdynamic;
06349    } else {
06350       return -1;
06351    }
06352 
06353 }

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

Definition at line 4292 of file app_meetme.c.

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

Referenced by load_module().

04293 {
04294    const char *actionid = astman_get_header(m, "ActionID");
04295    const char *conference = astman_get_header(m, "Conference");
04296    char idText[80] = "";
04297    struct ast_conference *cnf;
04298    struct ast_conf_user *user;
04299    int total = 0;
04300 
04301    if (!ast_strlen_zero(actionid))
04302       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04303 
04304    if (AST_LIST_EMPTY(&confs)) {
04305       astman_send_error(s, m, "No active conferences.");
04306       return 0;
04307    }
04308 
04309    astman_send_listack(s, m, "Meetme user list will follow", "start");
04310 
04311    /* Find the right conference */
04312    AST_LIST_LOCK(&confs);
04313    AST_LIST_TRAVERSE(&confs, cnf, list) {
04314       /* If we ask for one particular, and this isn't it, skip it */
04315       if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
04316          continue;
04317 
04318       /* Show all the users */
04319       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04320          total++;
04321          astman_append(s,
04322          "Event: MeetmeList\r\n"
04323          "%s"
04324          "Conference: %s\r\n"
04325          "UserNumber: %d\r\n"
04326          "CallerIDNum: %s\r\n"
04327          "CallerIDName: %s\r\n"
04328          "Channel: %s\r\n"
04329          "Admin: %s\r\n"
04330          "Role: %s\r\n"
04331          "MarkedUser: %s\r\n"
04332          "Muted: %s\r\n"
04333          "Talking: %s\r\n"
04334          "\r\n",
04335          idText,
04336          cnf->confno,
04337          user->user_no,
04338          S_OR(user->chan->cid.cid_num, "<unknown>"),
04339          S_OR(user->chan->cid.cid_name, "<no name>"),
04340          user->chan->name,
04341          user->userflags & CONFFLAG_ADMIN ? "Yes" : "No",
04342          user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen",
04343          user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No",
04344          user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
04345          user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored"); 
04346       }
04347    }
04348    AST_LIST_UNLOCK(&confs);
04349    /* Send final confirmation */
04350    astman_append(s,
04351    "Event: MeetmeListComplete\r\n"
04352    "EventList: Complete\r\n"
04353    "ListItems: %d\r\n"
04354    "%s"
04355    "\r\n", total, idText);
04356    return 0;
04357 }

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

Definition at line 4274 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04275 {
04276    return meetmemute(s, m, 1);
04277 }

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

Definition at line 4279 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04280 {
04281    return meetmemute(s, m, 0);
04282 }

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

The MeetMeadmin application.

Definition at line 3969 of file app_meetme.c.

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

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

03969                                                             {
03970    char *params;
03971    struct ast_conference *cnf;
03972    struct ast_conf_user *user = NULL;
03973    AST_DECLARE_APP_ARGS(args,
03974       AST_APP_ARG(confno);
03975       AST_APP_ARG(command);
03976       AST_APP_ARG(user);
03977    );
03978    int res = 0;
03979 
03980    if (ast_strlen_zero(data)) {
03981       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
03982       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
03983       return -1;
03984    }
03985 
03986    params = ast_strdupa(data);
03987    AST_STANDARD_APP_ARGS(args, params);
03988 
03989    if (!args.command) {
03990       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
03991       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
03992       return -1;
03993    }
03994 
03995    AST_LIST_LOCK(&confs);
03996    AST_LIST_TRAVERSE(&confs, cnf, list) {
03997       if (!strcmp(cnf->confno, args.confno))
03998          break;
03999    }
04000 
04001    if (!cnf) {
04002       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
04003       AST_LIST_UNLOCK(&confs);
04004       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
04005       return 0;
04006    }
04007 
04008    ast_atomic_fetchadd_int(&cnf->refcount, 1);
04009 
04010    if (args.user)
04011       user = find_user(cnf, args.user);
04012 
04013    switch (*args.command) {
04014    case 76: /* L: Lock */ 
04015       cnf->locked = 1;
04016       break;
04017    case 108: /* l: Unlock */ 
04018       cnf->locked = 0;
04019       break;
04020    case 75: /* K: kick all users */
04021       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
04022          user->adminflags |= ADMINFLAG_KICKME;
04023       break;
04024    case 101: /* e: Eject last user*/
04025       user = AST_LIST_LAST(&cnf->userlist);
04026       if (!(user->userflags & CONFFLAG_ADMIN))
04027          user->adminflags |= ADMINFLAG_KICKME;
04028       else {
04029          res = -1;
04030          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
04031       }
04032       break;
04033    case 77: /* M: Mute */ 
04034       if (user) {
04035          user->adminflags |= ADMINFLAG_MUTED;
04036       } else {
04037          res = -2;
04038          ast_log(LOG_NOTICE, "Specified User not found!\n");
04039       }
04040       break;
04041    case 78: /* N: Mute all (non-admin) users */
04042       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04043          if (!(user->userflags & CONFFLAG_ADMIN)) {
04044             user->adminflags |= ADMINFLAG_MUTED;
04045          }
04046       }
04047       break;               
04048    case 109: /* m: Unmute */ 
04049       if (user) {
04050          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04051       } else {
04052          res = -2;
04053          ast_log(LOG_NOTICE, "Specified User not found!\n");
04054       }
04055       break;
04056    case 110: /* n: Unmute all users */
04057       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04058          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04059       }
04060       break;
04061    case 107: /* k: Kick user */ 
04062       if (user) {
04063          user->adminflags |= ADMINFLAG_KICKME;
04064       } else {
04065          res = -2;
04066          ast_log(LOG_NOTICE, "Specified User not found!\n");
04067       }
04068       break;
04069    case 118: /* v: Lower all users listen volume */
04070       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04071          tweak_listen_volume(user, VOL_DOWN);
04072       }
04073       break;
04074    case 86: /* V: Raise all users listen volume */
04075       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04076          tweak_listen_volume(user, VOL_UP);
04077       }
04078       break;
04079    case 115: /* s: Lower all users speaking volume */
04080       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04081          tweak_talk_volume(user, VOL_DOWN);
04082       }
04083       break;
04084    case 83: /* S: Raise all users speaking volume */
04085       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04086          tweak_talk_volume(user, VOL_UP);
04087       }
04088       break;
04089    case 82: /* R: Reset all volume levels */
04090       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04091          reset_volumes(user);
04092       }
04093       break;
04094    case 114: /* r: Reset user's volume level */
04095       if (user) {
04096          reset_volumes(user);
04097       } else {
04098          res = -2;
04099          ast_log(LOG_NOTICE, "Specified User not found!\n");
04100       }
04101       break;
04102    case 85: /* U: Raise user's listen volume */
04103       if (user) {
04104          tweak_listen_volume(user, VOL_UP);
04105       } else {
04106          res = -2;
04107          ast_log(LOG_NOTICE, "Specified User not found!\n");
04108       }
04109       break;
04110    case 117: /* u: Lower user's listen volume */
04111       if (user) {
04112          tweak_listen_volume(user, VOL_DOWN);
04113       } else {
04114          res = -2;
04115          ast_log(LOG_NOTICE, "Specified User not found!\n");
04116       }
04117       break;
04118    case 84: /* T: Raise user's talk volume */
04119       if (user) {
04120          tweak_talk_volume(user, VOL_UP);
04121       } else {
04122          res = -2;
04123          ast_log(LOG_NOTICE, "Specified User not found!\n");
04124       }
04125       break;
04126    case 116: /* t: Lower user's talk volume */
04127       if (user) {
04128          tweak_talk_volume(user, VOL_DOWN);
04129       } else {
04130          res = -2;
04131          ast_log(LOG_NOTICE, "Specified User not found!\n");
04132       }
04133       break;
04134    case 'E': /* E: Extend conference */
04135       if (rt_extend_conf(args.confno)) {
04136          res = -1;
04137       }
04138       break;
04139    }
04140 
04141    AST_LIST_UNLOCK(&confs);
04142 
04143    dispose_conf(cnf);
04144    pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
04145 
04146    return 0;
04147 }

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

Definition at line 1907 of file app_meetme.c.

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

Referenced by conf_run().

01908 {
01909    struct announce_listitem *current;
01910    struct ast_conference *conf = data;
01911    int res;
01912    char filename[PATH_MAX] = "";
01913    AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
01914    AST_LIST_HEAD_INIT_NOLOCK(&local_list);
01915 
01916    while (!conf->announcethread_stop) {
01917       ast_mutex_lock(&conf->announcelistlock);
01918       if (conf->announcethread_stop) {
01919          ast_mutex_unlock(&conf->announcelistlock);
01920          break;
01921       }
01922       if (AST_LIST_EMPTY(&conf->announcelist))
01923          ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
01924 
01925       AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
01926       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01927 
01928       ast_mutex_unlock(&conf->announcelistlock);
01929       if (conf->announcethread_stop) {
01930          break;
01931       }
01932 
01933       for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
01934          ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
01935          if (!ast_fileexists(current->namerecloc, NULL, NULL))
01936             continue;
01937          if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
01938             if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
01939                res = ast_waitstream(current->confchan, "");
01940             if (!res) {
01941                ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
01942                if (!ast_streamfile(current->confchan, filename, current->language))
01943                   ast_waitstream(current->confchan, "");
01944             }
01945          }
01946          if (current->announcetype == CONF_HASLEFT) {
01947             ast_filedelete(current->namerecloc, NULL);
01948          }
01949       }
01950    }
01951 
01952    /* thread marked to stop, clean up */
01953    while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
01954       ast_filedelete(current->namerecloc, NULL);
01955       ao2_ref(current, -1);
01956    }
01957    return NULL;
01958 }

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

Definition at line 4667 of file app_meetme.c.

References ast_answer(), and ast_indicate().

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

04668 {
04669    ast_answer(chan);
04670    ast_indicate(chan, -1);
04671 }

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

Find or create a conference.

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

Definition at line 1061 of file app_meetme.c.

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

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

01062 {
01063    struct ast_conference *cnf;
01064    struct dahdi_confinfo dahdic = { 0, };
01065    int confno_int = 0;
01066 
01067    AST_LIST_LOCK(&confs);
01068 
01069    AST_LIST_TRAVERSE(&confs, cnf, list) {
01070       if (!strcmp(confno, cnf->confno)) 
01071          break;
01072    }
01073 
01074    if (cnf || (!make && !dynamic))
01075       goto cnfout;
01076 
01077    /* Make a new one */
01078    if (!(cnf = ast_calloc(1, sizeof(*cnf))))
01079       goto cnfout;
01080 
01081    ast_mutex_init(&cnf->playlock);
01082    ast_mutex_init(&cnf->listenlock);
01083    cnf->recordthread = AST_PTHREADT_NULL;
01084    ast_mutex_init(&cnf->recordthreadlock);
01085    cnf->announcethread = AST_PTHREADT_NULL;
01086    ast_mutex_init(&cnf->announcethreadlock);
01087    ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
01088    ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
01089    ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
01090    ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid));
01091 
01092    /* Setup a new dahdi conference */
01093    dahdic.confno = -1;
01094    dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01095    cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
01096    if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
01097       ast_log(LOG_WARNING, "Unable to open pseudo device\n");
01098       if (cnf->fd >= 0)
01099          close(cnf->fd);
01100       ast_free(cnf);
01101       cnf = NULL;
01102       goto cnfout;
01103    }
01104 
01105    cnf->dahdiconf = dahdic.confno;
01106 
01107    /* Setup a new channel for playback of audio files */
01108    cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL);
01109    if (cnf->chan) {
01110       ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
01111       ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
01112       dahdic.chan = 0;
01113       dahdic.confno = cnf->dahdiconf;
01114       dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01115       if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
01116          ast_log(LOG_WARNING, "Error setting conference\n");
01117          if (cnf->chan)
01118             ast_hangup(cnf->chan);
01119          else
01120             close(cnf->fd);
01121 
01122          ast_free(cnf);
01123          cnf = NULL;
01124          goto cnfout;
01125       }
01126    }
01127 
01128    /* Fill the conference struct */
01129    cnf->start = time(NULL);
01130    cnf->maxusers = 0x7fffffff;
01131    cnf->isdynamic = dynamic ? 1 : 0;
01132    ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
01133    AST_LIST_INSERT_HEAD(&confs, cnf, list);
01134 
01135    /* Reserve conference number in map */
01136    if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01137       conf_map[confno_int] = 1;
01138    
01139 cnfout:
01140    if (cnf)
01141       ast_atomic_fetchadd_int(&cnf->refcount, refcount);
01142 
01143    AST_LIST_UNLOCK(&confs);
01144 
01145    return cnf;
01146 }

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

Definition at line 1960 of file app_meetme.c.

References ast_channel::_state, AST_STATE_UP, and CONFFLAG_NO_AUDIO_UNTIL_UP.

Referenced by conf_run().

01961 {
01962    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01963       return 1;
01964    }
01965 
01966    return (chan->_state == AST_STATE_UP);
01967 }

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

Definition at line 895 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

Referenced by conf_play(), and conf_run().

00896 {
00897    int res;
00898    int x;
00899 
00900    while (len) {
00901       if (block) {
00902          x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
00903          res = ioctl(fd, DAHDI_IOMUX, &x);
00904       } else
00905          res = 0;
00906       if (res >= 0)
00907          res = write(fd, data, len);
00908       if (res < 1) {
00909          if (errno != EAGAIN) {
00910             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00911             return -1;
00912          } else
00913             return 0;
00914       }
00915       len -= res;
00916       data += res;
00917    }
00918 
00919    return 0;
00920 }

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

Definition at line 4151 of file app_meetme.c.

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

Referenced by load_module().

04151                                                                     {
04152    char *params;
04153    struct ast_conference *conf = NULL;
04154    struct ast_conf_user *user = NULL;
04155    AST_DECLARE_APP_ARGS(args,
04156       AST_APP_ARG(channel);
04157       AST_APP_ARG(command);
04158    );
04159 
04160    if (ast_strlen_zero(data)) {
04161       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
04162       return -1;
04163    }
04164    
04165    params = ast_strdupa(data);
04166    AST_STANDARD_APP_ARGS(args, params);
04167 
04168    if (!args.channel) {
04169       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
04170       return -1;
04171    }
04172 
04173    if (!args.command) {
04174       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
04175       return -1;
04176    }
04177 
04178    AST_LIST_LOCK(&confs);
04179    AST_LIST_TRAVERSE(&confs, conf, list) {
04180       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
04181          if (!strcmp(user->chan->name, args.channel))
04182             break;
04183       }
04184    }
04185    
04186    if (!user) {
04187       ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
04188       AST_LIST_UNLOCK(&confs);
04189       return 0;
04190    }
04191    
04192    /* perform the specified action */
04193    switch (*args.command) {
04194       case 77: /* M: Mute */ 
04195          user->adminflags |= ADMINFLAG_MUTED;
04196          break;
04197       case 109: /* m: Unmute */ 
04198          user->adminflags &= ~ADMINFLAG_MUTED;
04199          break;
04200       case 107: /* k: Kick user */ 
04201          user->adminflags |= ADMINFLAG_KICKME;
04202          break;
04203       default: /* unknown command */
04204          ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
04205          break;
04206    }
04207 
04208    AST_LIST_UNLOCK(&confs);
04209    
04210    return 0;
04211 }

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

Definition at line 1148 of file app_meetme.c.

References ast_cli_complete(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_conference::confno, len(), ast_conf_user::list, ast_conf_user::user_no, and ast_conference::userlist.

Referenced by meetme_cmd(), and meetme_show_cmd().

01149 {
01150    static char *cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
01151 
01152    int len = strlen(word);
01153    int which = 0;
01154    struct ast_conference *cnf = NULL;
01155    struct ast_conf_user *usr = NULL;
01156    char *confno = NULL;
01157    char usrno[50] = "";
01158    char *myline, *ret = NULL;
01159    
01160    if (pos == 1) {      /* Command */
01161       return ast_cli_complete(word, cmds, state);
01162    } else if (pos == 2) {  /* Conference Number */
01163       AST_LIST_LOCK(&confs);
01164       AST_LIST_TRAVERSE(&confs, cnf, list) {
01165          if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
01166             ret = cnf->confno;
01167             break;
01168          }
01169       }
01170       ret = ast_strdup(ret); /* dup before releasing the lock */
01171       AST_LIST_UNLOCK(&confs);
01172       return ret;
01173    } else if (pos == 3) {
01174       /* User Number || Conf Command option*/
01175       if (strstr(line, "mute") || strstr(line, "kick")) {
01176          if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
01177             return ast_strdup("all");
01178          which++;
01179          AST_LIST_LOCK(&confs);
01180 
01181          /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
01182          myline = ast_strdupa(line);
01183          if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
01184             while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
01185                ;
01186          }
01187          
01188          AST_LIST_TRAVERSE(&confs, cnf, list) {
01189             if (!strcmp(confno, cnf->confno))
01190                 break;
01191          }
01192 
01193          if (cnf) {
01194             /* Search for the user */
01195             AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
01196                snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
01197                if (!strncasecmp(word, usrno, len) && ++which > state)
01198                   break;
01199             }
01200          }
01201          AST_LIST_UNLOCK(&confs);
01202          return usr ? ast_strdup(usrno) : NULL;
01203       }
01204    }
01205 
01206    return NULL;
01207 }

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

The meetme() application.

Definition at line 3696 of file app_meetme.c.

References ast_channel::_state, ast_conference::adminopts, 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_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_variable_browse(), ast_verb, ast_waitstream(), conf_map, conf_run(), CONFFLAG_ADMIN, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFFLAG_QUIET, CONFIG_FILE_NAME, config_flags, CONFIG_STATUS_FILEINVALID, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), ast_flags::flags, ast_channel::language, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, MAX_SETTINGS, meetme_opts, ast_variable::name, ast_variable::next, OPT_ARG_ARRAY_SIZE, parse(), ast_conference::pin, ast_conference::pinadmin, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::useropts, ast_variable::value, and var.

Referenced by load_module().

03697 {
03698    int res = -1;
03699    char confno[MAX_CONFNUM] = "";
03700    int allowretry = 0;
03701    int retrycnt = 0;
03702    struct ast_conference *cnf = NULL;
03703    struct ast_flags confflags = {0}, config_flags = { 0 };
03704    int dynamic = 0;
03705    int empty = 0, empty_no_pin = 0;
03706    int always_prompt = 0;
03707    char *notdata, *info, the_pin[MAX_PIN] = "";
03708    AST_DECLARE_APP_ARGS(args,
03709       AST_APP_ARG(confno);
03710       AST_APP_ARG(options);
03711       AST_APP_ARG(pin);
03712    );
03713    char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
03714 
03715    if (ast_strlen_zero(data)) {
03716       allowretry = 1;
03717       notdata = "";
03718    } else {
03719       notdata = data;
03720    }
03721    
03722    if (chan->_state != AST_STATE_UP)
03723       ast_answer(chan);
03724 
03725    info = ast_strdupa(notdata);
03726 
03727    AST_STANDARD_APP_ARGS(args, info);  
03728 
03729    if (args.confno) {
03730       ast_copy_string(confno, args.confno, sizeof(confno));
03731       if (ast_strlen_zero(confno)) {
03732          allowretry = 1;
03733       }
03734    }
03735    
03736    if (args.pin)
03737       ast_copy_string(the_pin, args.pin, sizeof(the_pin));
03738 
03739    if (args.options) {
03740       ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
03741       dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
03742       if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
03743          strcpy(the_pin, "q");
03744 
03745       empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
03746       empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
03747       always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
03748    }
03749 
03750    do {
03751       if (retrycnt > 3)
03752          allowretry = 0;
03753       if (empty) {
03754          int i;
03755          struct ast_config *cfg;
03756          struct ast_variable *var;
03757          int confno_int;
03758 
03759          /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
03760          if ((empty_no_pin) || (!dynamic)) {
03761             cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03762             if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03763                var = ast_variable_browse(cfg, "rooms");
03764                while (var) {
03765                   char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
03766                   if (!strcasecmp(var->name, "conf")) {
03767                      int found = 0;
03768                      ast_copy_string(parse, var->value, sizeof(parse));
03769                      confno_tmp = strsep(&stringp, "|,");
03770                      if (!dynamic) {
03771                         /* For static:  run through the list and see if this conference is empty */
03772                         AST_LIST_LOCK(&confs);
03773                         AST_LIST_TRAVERSE(&confs, cnf, list) {
03774                            if (!strcmp(confno_tmp, cnf->confno)) {
03775                               /* The conference exists, therefore it's not empty */
03776                               found = 1;
03777                               break;
03778                            }
03779                         }
03780                         AST_LIST_UNLOCK(&confs);
03781                         if (!found) {
03782                            /* At this point, we have a confno_tmp (static conference) that is empty */
03783                            if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
03784                               /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
03785                                * Case 2:  empty_no_pin and pin is blank (but not NULL)
03786                                * Case 3:  not empty_no_pin
03787                                */
03788                               ast_copy_string(confno, confno_tmp, sizeof(confno));
03789                               break;
03790                               /* XXX the map is not complete (but we do have a confno) */
03791                            }
03792                         }
03793                      }
03794                   }
03795                   var = var->next;
03796                }
03797                ast_config_destroy(cfg);
03798             }
03799          }
03800 
03801          /* Select first conference number not in use */
03802          if (ast_strlen_zero(confno) && dynamic) {
03803             AST_LIST_LOCK(&confs);
03804             for (i = 0; i < ARRAY_LEN(conf_map); i++) {
03805                if (!conf_map[i]) {
03806                   snprintf(confno, sizeof(confno), "%d", i);
03807                   conf_map[i] = 1;
03808                   break;
03809                }
03810             }
03811             AST_LIST_UNLOCK(&confs);
03812          }
03813 
03814          /* Not found? */
03815          if (ast_strlen_zero(confno)) {
03816             res = ast_streamfile(chan, "conf-noempty", chan->language);
03817             if (!res)
03818                ast_waitstream(chan, "");
03819          } else {
03820             if (sscanf(confno, "%30d", &confno_int) == 1) {
03821                if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
03822                   res = ast_streamfile(chan, "conf-enteringno", chan->language);
03823                   if (!res) {
03824                      ast_waitstream(chan, "");
03825                      res = ast_say_digits(chan, confno_int, "", chan->language);
03826                   }
03827                }
03828             } else {
03829                ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
03830             }
03831          }
03832       }
03833 
03834       while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
03835          /* Prompt user for conference number */
03836          res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
03837          if (res < 0) {
03838             /* Don't try to validate when we catch an error */
03839             confno[0] = '\0';
03840             allowretry = 0;
03841             break;
03842          }
03843       }
03844       if (!ast_strlen_zero(confno)) {
03845          /* Check the validity of the conference */
03846          cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
03847             sizeof(the_pin), 1, &confflags);
03848          if (!cnf) {
03849             int too_early = 0;
03850 
03851             cnf = find_conf_realtime(chan, confno, 1, dynamic, 
03852                the_pin, sizeof(the_pin), 1, &confflags,&too_early);
03853             if (rt_schedule && too_early)
03854                allowretry = 0;
03855          }
03856 
03857          if (!cnf) {
03858             if (allowretry) {
03859                confno[0] = '\0';
03860                res = ast_streamfile(chan, "conf-invalid", chan->language);
03861                if (!res)
03862                   ast_waitstream(chan, "");
03863                res = -1;
03864             }
03865          } else {
03866             if ((!ast_strlen_zero(cnf->pin) &&
03867                  !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
03868                 (!ast_strlen_zero(cnf->pinadmin) &&
03869                  ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
03870                char pin[MAX_PIN] = "";
03871                int j;
03872 
03873                /* Allow the pin to be retried up to 3 times */
03874                for (j = 0; j < 3; j++) {
03875                   if (*the_pin && (always_prompt == 0)) {
03876                      ast_copy_string(pin, the_pin, sizeof(pin));
03877                      res = 0;
03878                   } else {
03879                      /* Prompt user for pin if pin is required */
03880                      res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
03881                   }
03882                   if (res >= 0) {
03883                      if (!strcasecmp(pin, cnf->pin) ||
03884                          (!ast_strlen_zero(cnf->pinadmin) &&
03885                           !strcasecmp(pin, cnf->pinadmin))) {
03886                         /* Pin correct */
03887                         allowretry = 0;
03888                         if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
03889                            if (!ast_strlen_zero(cnf->adminopts)) {
03890                               char *opts = ast_strdupa(cnf->adminopts);
03891                               ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
03892                            }
03893                         } else {
03894                            if (!ast_strlen_zero(cnf->useropts)) {
03895                               char *opts = ast_strdupa(cnf->useropts);
03896                               ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
03897                            }
03898                         }
03899                         /* Run the conference */
03900                         ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
03901                         res = conf_run(chan, cnf, confflags.flags, optargs);
03902                         break;
03903                      } else {
03904                         /* Pin invalid */
03905                         if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
03906                            res = ast_waitstream(chan, AST_DIGIT_ANY);
03907                            ast_stopstream(chan);
03908                         } else {
03909                            ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
03910                            break;
03911                         }
03912                         if (res < 0)
03913                            break;
03914                         pin[0] = res;
03915                         pin[1] = '\0';
03916                         res = -1;
03917                         if (allowretry)
03918                            confno[0] = '\0';
03919                      }
03920                   } else {
03921                      /* failed when getting the pin */
03922                      res = -1;
03923                      allowretry = 0;
03924                      /* see if we need to get rid of the conference */
03925                      break;
03926                   }
03927 
03928                   /* Don't retry pin with a static pin */
03929                   if (*the_pin && (always_prompt == 0)) {
03930                      break;
03931                   }
03932                }
03933             } else {
03934                /* No pin required */
03935                allowretry = 0;
03936 
03937                /* Run the conference */
03938                res = conf_run(chan, cnf, confflags.flags, optargs);
03939             }
03940             dispose_conf(cnf);
03941             cnf = NULL;
03942          }
03943       }
03944    } while (allowretry);
03945 
03946    if (cnf)
03947       dispose_conf(cnf);
03948    
03949    return res;
03950 }

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

Definition at line 1617 of file app_meetme.c.

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

Referenced by conf_run().

01618 {
01619    int x;
01620 
01621    /* read any frames that may be waiting on the channel
01622       and throw them away
01623    */
01624    if (chan) {
01625       struct ast_frame *f;
01626 
01627       /* when no frames are available, this will wait
01628          for 1 millisecond maximum
01629       */
01630       while (ast_waitfor(chan, 1)) {
01631          f = ast_read(chan);
01632          if (f)
01633             ast_frfree(f);
01634          else /* channel was hung up or something else happened */
01635             break;
01636       }
01637    }
01638 
01639    /* flush any data sitting in the pseudo channel */
01640    x = DAHDI_FLUSH_ALL;
01641    if (ioctl(fd, DAHDI_FLUSH, &x))
01642       ast_log(LOG_WARNING, "Error flushing channel\n");
01643 
01644 }

static int conf_free ( struct ast_conference conf  )  [static]

Definition at line 1648 of file app_meetme.c.

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

Referenced by dispose_conf().

01649 {
01650    int x;
01651    struct announce_listitem *item;
01652    
01653    AST_LIST_REMOVE(&confs, conf, list);
01654    manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01655 
01656    if (conf->recording == MEETME_RECORD_ACTIVE) {
01657       conf->recording = MEETME_RECORD_TERMINATE;
01658       AST_LIST_UNLOCK(&confs);
01659       while (1) {
01660          usleep(1);
01661          AST_LIST_LOCK(&confs);
01662          if (conf->recording == MEETME_RECORD_OFF)
01663             break;
01664          AST_LIST_UNLOCK(&confs);
01665       }
01666    }
01667 
01668    for (x = 0; x < AST_FRAME_BITS; x++) {
01669       if (conf->transframe[x])
01670          ast_frfree(conf->transframe[x]);
01671       if (conf->transpath[x])
01672          ast_translator_free_path(conf->transpath[x]);
01673    }
01674    if (conf->announcethread != AST_PTHREADT_NULL) {
01675       ast_mutex_lock(&conf->announcelistlock);
01676       conf->announcethread_stop = 1;
01677       ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01678       ast_cond_signal(&conf->announcelist_addition);
01679       ast_mutex_unlock(&conf->announcelistlock);
01680       pthread_join(conf->announcethread, NULL);
01681    
01682       while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01683          ast_filedelete(item->namerecloc, NULL);
01684          ao2_ref(item, -1);
01685       }
01686       ast_mutex_destroy(&conf->announcelistlock);
01687    }
01688    if (conf->origframe)
01689       ast_frfree(conf->origframe);
01690    if (conf->lchan)
01691       ast_hangup(conf->lchan);
01692    if (conf->chan)
01693       ast_hangup(conf->chan);
01694    if (conf->fd >= 0)
01695       close(conf->fd);
01696    if (conf->recordingfilename) {
01697       ast_free(conf->recordingfilename);
01698    }
01699    if (conf->recordingformat) {
01700       ast_free(conf->recordingformat);
01701    }
01702    ast_mutex_destroy(&conf->playlock);
01703    ast_mutex_destroy(&conf->listenlock);
01704    ast_mutex_destroy(&conf->recordthreadlock);
01705    ast_mutex_destroy(&conf->announcethreadlock);
01706    ast_free(conf);
01707 
01708    return 0;
01709 }

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

Definition at line 1013 of file app_meetme.c.

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

Referenced by conf_run().

01014 {
01015    unsigned char *data;
01016    int len;
01017    int res = -1;
01018 
01019    if (!ast_check_hangup(chan))
01020       res = ast_autoservice_start(chan);
01021 
01022    AST_LIST_LOCK(&confs);
01023 
01024    switch(sound) {
01025    case ENTER:
01026       data = enter;
01027       len = sizeof(enter);
01028       break;
01029    case LEAVE:
01030       data = leave;
01031       len = sizeof(leave);
01032       break;
01033    default:
01034       data = NULL;
01035       len = 0;
01036    }
01037    if (data) {
01038       careful_write(conf->fd, data, len, 1);
01039    }
01040 
01041    AST_LIST_UNLOCK(&confs);
01042 
01043    if (!res) 
01044       ast_autoservice_stop(chan);
01045 }

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

Definition at line 1711 of file app_meetme.c.

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

Referenced by conf_run().

01713 {
01714    struct ast_conf_user *user;
01715 
01716    AST_LIST_TRAVERSE(&conf->userlist, user, list) {
01717       if (user == sender)
01718          continue;
01719       if (ast_write(user->chan, f) < 0)
01720          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01721    }
01722 }

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

Definition at line 1998 of file app_meetme.c.

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

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

01999 {
02000    struct ast_conf_user *user = NULL;
02001    struct ast_conf_user *usr = NULL;
02002    int fd;
02003    struct dahdi_confinfo dahdic, dahdic_empty;
02004    struct ast_frame *f;
02005    struct ast_channel *c;
02006    struct ast_frame fr;
02007    int outfd;
02008    int ms;
02009    int nfds;
02010    int res;
02011    int retrydahdi;
02012    int origfd;
02013    int musiconhold = 0, mohtempstopped = 0;
02014    int firstpass = 0;
02015    int lastmarked = 0;
02016    int currentmarked = 0;
02017    int ret = -1;
02018    int x;
02019    int menu_active = 0;
02020    int talkreq_manager = 0;
02021    int using_pseudo = 0;
02022    int duration = 20;
02023    int hr, min, sec;
02024    int sent_event = 0;
02025    int checked = 0;
02026    int announcement_played = 0;
02027    struct timeval now;
02028    struct ast_dsp *dsp = NULL;
02029    struct ast_app *agi_app;
02030    char *agifile;
02031    const char *agifiledefault = "conf-background.agi", *tmpvar;
02032    char meetmesecs[30] = "";
02033    char exitcontext[AST_MAX_CONTEXT] = "";
02034    char recordingtmp[AST_MAX_EXTENSION] = "";
02035    char members[10] = "";
02036    int dtmf, opt_waitmarked_timeout = 0;
02037    time_t timeout = 0;
02038    struct dahdi_bufferinfo bi;
02039    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
02040    char *buf = __buf + AST_FRIENDLY_OFFSET;
02041    char *exitkeys = NULL;
02042    unsigned int calldurationlimit = 0;
02043    long timelimit = 0;
02044    long play_warning = 0;
02045    long warning_freq = 0;
02046    const char *warning_sound = NULL;
02047    const char *end_sound = NULL;
02048    char *parse;   
02049    long time_left_ms = 0;
02050    struct timeval nexteventts = { 0, };
02051    int to;
02052    int setusercount = 0;
02053    int confsilence = 0, totalsilence = 0;
02054 
02055    if (!(user = ast_calloc(1, sizeof(*user))))
02056       return ret;
02057 
02058    /* Possible timeout waiting for marked user */
02059    if ((confflags & CONFFLAG_WAITMARKED) &&
02060       !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
02061       (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
02062       (opt_waitmarked_timeout > 0)) {
02063       timeout = time(NULL) + opt_waitmarked_timeout;
02064    }
02065       
02066    if ((confflags & CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
02067       calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
02068       ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
02069    }
02070    
02071    if ((confflags & CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
02072       char *limit_str, *warning_str, *warnfreq_str;
02073       const char *var;
02074  
02075       parse = optargs[OPT_ARG_DURATION_LIMIT];
02076       limit_str = strsep(&parse, ":");
02077       warning_str = strsep(&parse, ":");
02078       warnfreq_str = parse;
02079  
02080       timelimit = atol(limit_str);
02081       if (warning_str)
02082          play_warning = atol(warning_str);
02083       if (warnfreq_str)
02084          warning_freq = atol(warnfreq_str);
02085  
02086       if (!timelimit) {
02087          timelimit = play_warning = warning_freq = 0;
02088          warning_sound = NULL;
02089       } else if (play_warning > timelimit) {       
02090          if (!warning_freq) {
02091             play_warning = 0;
02092          } else {
02093             while (play_warning > timelimit)
02094                play_warning -= warning_freq;
02095             if (play_warning < 1)
02096                play_warning = warning_freq = 0;
02097          }
02098       }
02099       
02100       ast_channel_lock(chan);
02101       if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
02102          var = ast_strdupa(var);
02103       }
02104       ast_channel_unlock(chan);
02105 
02106       warning_sound = var ? var : "timeleft";
02107       
02108       ast_channel_lock(chan);
02109       if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
02110          var = ast_strdupa(var);
02111       }
02112       ast_channel_unlock(chan);
02113       
02114       end_sound = var ? var : NULL;
02115          
02116       /* undo effect of S(x) in case they are both used */
02117       calldurationlimit = 0;
02118       /* more efficient do it like S(x) does since no advanced opts */
02119       if (!play_warning && !end_sound && timelimit) { 
02120          calldurationlimit = timelimit / 1000;
02121          timelimit = play_warning = warning_freq = 0;
02122       } else {
02123          ast_debug(2, "Limit Data for this call:\n");
02124          ast_debug(2, "- timelimit     = %ld\n", timelimit);
02125          ast_debug(2, "- play_warning  = %ld\n", play_warning);
02126          ast_debug(2, "- warning_freq  = %ld\n", warning_freq);
02127          ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
02128          ast_debug(2, "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
02129       }
02130    }
02131 
02132    /* Get exit keys */
02133    if ((confflags & CONFFLAG_KEYEXIT)) {
02134       if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
02135          exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
02136       else
02137          exitkeys = ast_strdupa("#"); /* Default */
02138    }
02139    
02140    if (confflags & CONFFLAG_RECORDCONF) {
02141       if (!conf->recordingfilename) {
02142          const char *var;
02143          ast_channel_lock(chan);
02144          if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
02145             conf->recordingfilename = ast_strdup(var);
02146          }
02147          if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
02148             conf->recordingformat = ast_strdup(var);
02149          }
02150          ast_channel_unlock(chan);
02151          if (!conf->recordingfilename) {
02152             snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
02153             conf->recordingfilename = ast_strdup(recordingtmp);
02154          }
02155          if (!conf->recordingformat) {
02156             conf->recordingformat = ast_strdup("wav");
02157          }
02158          ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
02159                 conf->confno, conf->recordingfilename, conf->recordingformat);
02160       }
02161    }
02162 
02163    ast_mutex_lock(&conf->recordthreadlock);
02164    if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
02165       ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
02166       ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
02167       dahdic.chan = 0;
02168       dahdic.confno = conf->dahdiconf;
02169       dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
02170       if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
02171          ast_log(LOG_WARNING, "Error starting listen channel\n");
02172          ast_hangup(conf->lchan);
02173          conf->lchan = NULL;
02174       } else {
02175          ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
02176       }
02177    }
02178    ast_mutex_unlock(&conf->recordthreadlock);
02179 
02180    ast_mutex_lock(&conf->announcethreadlock);
02181    if ((conf->announcethread == AST_PTHREADT_NULL) && !(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
02182       ast_mutex_init(&conf->announcelistlock);
02183       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
02184       ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
02185    }
02186    ast_mutex_unlock(&conf->announcethreadlock);
02187 
02188    time(&user->jointime);
02189    
02190    user->timelimit = timelimit;
02191    user->play_warning = play_warning;
02192    user->warning_freq = warning_freq;
02193    user->warning_sound = warning_sound;
02194    user->end_sound = end_sound;  
02195    
02196    if (calldurationlimit > 0) {
02197       time(&user->kicktime);
02198       user->kicktime = user->kicktime + calldurationlimit;
02199    }
02200    
02201    if (ast_tvzero(user->start_time))
02202       user->start_time = ast_tvnow();
02203    time_left_ms = user->timelimit;
02204    
02205    if (user->timelimit) {
02206       nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
02207       nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
02208    }
02209 
02210    if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
02211       /* Sorry, but this conference is locked! */  
02212       if (!ast_streamfile(chan, "conf-locked", chan->language))
02213          ast_waitstream(chan, "");
02214       goto outrun;
02215    }
02216 
02217       ast_mutex_lock(&conf->playlock);
02218 
02219    if (AST_LIST_EMPTY(&conf->userlist))
02220       user->user_no = 1;
02221    else
02222       user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
02223 
02224    if (rt_schedule && conf->maxusers)
02225       if (conf->users >= conf->maxusers) {
02226          /* Sorry, but this confernce has reached the participant limit! */   
02227          if (!ast_streamfile(chan, "conf-full", chan->language))
02228             ast_waitstream(chan, "");
02229          ast_mutex_unlock(&conf->playlock);
02230          user->user_no = 0;
02231          goto outrun;
02232       }
02233 
02234    AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
02235 
02236    user->chan = chan;
02237    user->userflags = confflags;
02238    user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
02239    user->talking = -1;
02240 
02241    ast_mutex_unlock(&conf->playlock);
02242 
02243    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
02244       char destdir[PATH_MAX];
02245 
02246       snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
02247 
02248       if (ast_mkdir(destdir, 0777) != 0) {
02249          ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
02250          goto outrun;
02251       }
02252 
02253       snprintf(user->namerecloc, sizeof(user->namerecloc),
02254           "%s/meetme-username-%s-%d", destdir,
02255           conf->confno, user->user_no);
02256       if (confflags & CONFFLAG_INTROUSERNOREVIEW)
02257          res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
02258       else
02259          res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
02260       if (res == -1)
02261          goto outrun;
02262    }
02263 
02264    ast_mutex_lock(&conf->playlock);
02265 
02266    if (confflags & CONFFLAG_MARKEDUSER)
02267       conf->markedusers++;
02268    conf->users++;
02269    if (rt_log_members) {
02270       /* Update table */
02271       snprintf(members, sizeof(members), "%d", conf->users);
02272       ast_realtime_require_field("meetme",
02273          "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
02274          "members", RQ_UINTEGER1, strlen(members),
02275          NULL);
02276       ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
02277    }
02278    setusercount = 1;
02279 
02280    /* This device changed state now - if this is the first user */
02281    if (conf->users == 1)
02282       ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
02283 
02284    ast_mutex_unlock(&conf->playlock);
02285 
02286    /* return the unique ID of the conference */
02287    pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
02288 
02289    if (confflags & CONFFLAG_EXIT_CONTEXT) {
02290       ast_channel_lock(chan);
02291       if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
02292          ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
02293       } else if (!ast_strlen_zero(chan->macrocontext)) {
02294          ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
02295       } else {
02296          ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
02297       }
02298       ast_channel_unlock(chan);
02299    }
02300 
02301    if (!(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
02302       if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
02303          if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
02304             ast_waitstream(chan, "");
02305       if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
02306          if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
02307             ast_waitstream(chan, "");
02308    }
02309 
02310    if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
02311       int keepplaying = 1;
02312 
02313       if (conf->users == 2) { 
02314          if (!ast_streamfile(chan, "conf-onlyone", chan->language)) {
02315             res = ast_waitstream(chan, AST_DIGIT_ANY);
02316             ast_stopstream(chan);
02317             if (res > 0)
02318                keepplaying = 0;
02319             else if (res == -1)
02320                goto outrun;
02321          }
02322       } else { 
02323          if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
02324             res = ast_waitstream(chan, AST_DIGIT_ANY);
02325             ast_stopstream(chan);
02326             if (res > 0)
02327                keepplaying = 0;
02328             else if (res == -1)
02329                goto outrun;
02330          }
02331          if (keepplaying) {
02332             res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
02333             if (res > 0)
02334                keepplaying = 0;
02335             else if (res == -1)
02336                goto outrun;
02337          }
02338          if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
02339             res = ast_waitstream(chan, AST_DIGIT_ANY);
02340             ast_stopstream(chan);
02341             if (res > 0)
02342                keepplaying = 0;
02343             else if (res == -1) 
02344                goto outrun;
02345          }
02346       }
02347    }
02348 
02349    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02350       /* We're leaving this alone until the state gets changed to up */
02351       ast_indicate(chan, -1);
02352    }
02353 
02354    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
02355       ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
02356       goto outrun;
02357    }
02358 
02359    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
02360       ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
02361       goto outrun;
02362    }
02363 
02364    retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
02365    user->dahdichannel = !retrydahdi;
02366 
02367  dahdiretry:
02368    origfd = chan->fds[0];
02369    if (retrydahdi) {
02370       /* open pseudo in non-blocking mode */
02371       fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
02372       if (fd < 0) {
02373          ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
02374          goto outrun;
02375       }
02376       using_pseudo = 1;
02377       /* Setup buffering information */
02378       memset(&bi, 0, sizeof(bi));
02379       bi.bufsize = CONF_SIZE / 2;
02380       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
02381       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
02382       bi.numbufs = audio_buffers;
02383       if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
02384          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
02385          close(fd);
02386          goto outrun;
02387       }
02388       x = 1;
02389       if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
02390          ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
02391          close(fd);
02392          goto outrun;
02393       }
02394       nfds = 1;
02395    } else {
02396       /* XXX Make sure we're not running on a pseudo channel XXX */
02397       fd = chan->fds[0];
02398       nfds = 0;
02399    }
02400    memset(&dahdic, 0, sizeof(dahdic));
02401    memset(&dahdic_empty, 0, sizeof(dahdic_empty));
02402    /* Check to see if we're in a conference... */
02403    dahdic.chan = 0;  
02404    if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
02405       ast_log(LOG_WARNING, "Error getting conference\n");
02406       close(fd);
02407       goto outrun;
02408    }
02409    if (dahdic.confmode) {
02410       /* Whoa, already in a conference...  Retry... */
02411       if (!retrydahdi) {
02412          ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
02413          retrydahdi = 1;
02414          goto dahdiretry;
02415       }
02416    }
02417    memset(&dahdic, 0, sizeof(dahdic));
02418    /* Add us to the conference */
02419    dahdic.chan = 0;  
02420    dahdic.confno = conf->dahdiconf;
02421 
02422    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02423       struct announce_listitem *item;
02424       if (!(item = ao2_alloc(sizeof(*item), NULL)))
02425          return -1;
02426       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02427       ast_copy_string(item->language, chan->language, sizeof(item->language));
02428       item->confchan = conf->chan;
02429       item->confusers = conf->users;
02430       item->announcetype = CONF_HASJOIN;
02431       ast_mutex_lock(&conf->announcelistlock);
02432       ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
02433       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02434       ast_cond_signal(&conf->announcelist_addition);
02435       ast_mutex_unlock(&conf->announcelistlock);
02436 
02437       while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
02438          ;
02439       }
02440       ao2_ref(item, -1);
02441    }
02442 
02443    if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers)
02444       dahdic.confmode = DAHDI_CONF_CONF;
02445    else if (confflags & CONFFLAG_MONITOR)
02446       dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02447    else if (confflags & CONFFLAG_TALKER)
02448       dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02449    else 
02450       dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02451 
02452    if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02453       ast_log(LOG_WARNING, "Error setting conference\n");
02454       close(fd);
02455       goto outrun;
02456    }
02457    ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf);
02458 
02459    if (!sent_event) {
02460       manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
02461                  "Channel: %s\r\n"
02462                  "Uniqueid: %s\r\n"
02463             "Meetme: %s\r\n"
02464             "Usernum: %d\r\n"
02465             "CallerIDnum: %s\r\n"
02466                   "CallerIDname: %s\r\n",
02467                   chan->name, chan->uniqueid, conf->confno, 
02468             user->user_no,
02469             S_OR(user->chan->cid.cid_num, "<unknown>"),
02470             S_OR(user->chan->cid.cid_name, "<unknown>")
02471             );
02472       sent_event = 1;
02473    }
02474 
02475    if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
02476       firstpass = 1;
02477       if (!(confflags & CONFFLAG_QUIET))
02478          if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
02479             conf_play(chan, conf, ENTER);
02480    }
02481 
02482    conf_flush(fd, chan);
02483 
02484    if (!(dsp = ast_dsp_new())) {
02485       ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
02486       res = -1;
02487    }
02488 
02489    if (confflags & CONFFLAG_AGI) {
02490       /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
02491          or use default filename of conf-background.agi */
02492 
02493       ast_channel_lock(chan);
02494       if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
02495          agifile = ast_strdupa(tmpvar);
02496       } else {
02497          agifile = ast_strdupa(agifiledefault);
02498       }
02499       ast_channel_unlock(chan);
02500       
02501       if (user->dahdichannel) {
02502          /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
02503          x = 1;
02504          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02505       }
02506       /* Find a pointer to the agi app and execute the script */
02507       agi_app = pbx_findapp("agi");
02508       if (agi_app) {
02509          ret = pbx_exec(chan, agi_app, agifile);
02510       } else {
02511          ast_log(LOG_WARNING, "Could not find application (agi)\n");
02512          ret = -2;
02513       }
02514       if (user->dahdichannel) {
02515          /*  Remove CONFMUTE mode on DAHDI channel */
02516          x = 0;
02517          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02518       }
02519    } else {
02520       if (user->dahdichannel && (confflags & CONFFLAG_STARMENU)) {
02521          /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
02522          x = 1;
02523          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02524       }  
02525       for (;;) {
02526          int menu_was_active = 0;
02527 
02528          outfd = -1;
02529          ms = -1;
02530          now = ast_tvnow();
02531 
02532          if (rt_schedule && conf->endtime) {
02533             char currenttime[32];
02534             long localendtime = 0;
02535             int extended = 0;
02536             struct ast_tm tm;
02537             struct ast_variable *var, *origvar;
02538             struct timeval tmp;
02539 
02540             if (now.tv_sec % 60 == 0) {
02541                if (!checked) {
02542                   ast_localtime(&now, &tm, NULL);
02543                   ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02544                   var = origvar = ast_load_realtime("meetme", "confno",
02545                      conf->confno, "starttime <=", currenttime,
02546                       "endtime >=", currenttime, NULL);
02547 
02548                   for ( ; var; var = var->next) {
02549                      if (!strcasecmp(var->name, "endtime")) {
02550                         struct ast_tm endtime_tm;
02551                         ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
02552                         tmp = ast_mktime(&endtime_tm, NULL);
02553                         localendtime = tmp.tv_sec;
02554                      }
02555                   }
02556                   ast_variables_destroy(origvar);
02557 
02558                   /* A conference can be extended from the
02559                      Admin/User menu or by an external source */
02560                   if (localendtime > conf->endtime){
02561                      conf->endtime = localendtime;
02562                      extended = 1;
02563                   }
02564 
02565                   if (conf->endtime && (now.tv_sec >= conf->endtime)) {
02566                      ast_verbose("Quitting time...\n");
02567                      goto outrun;
02568                   }
02569 
02570                   if (!announcement_played && conf->endalert) {
02571                      if (now.tv_sec + conf->endalert >= conf->endtime) {
02572                         if (!ast_streamfile(chan, "conf-will-end-in", chan->language))
02573                            ast_waitstream(chan, "");
02574                         ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language);
02575                         if (!ast_streamfile(chan, "minutes", chan->language))
02576                            ast_waitstream(chan, "");
02577                         announcement_played = 1;
02578                      }
02579                   }
02580 
02581                   if (extended) {
02582                      announcement_played = 0;
02583                   }
02584 
02585                   checked = 1;
02586                }
02587             } else {
02588                checked = 0;
02589             }
02590          }
02591 
02592          if (user->kicktime && (user->kicktime <= now.tv_sec)) {
02593             break;
02594          }
02595   
02596          to = -1;
02597          if (user->timelimit) {
02598             int minutes = 0, seconds = 0, remain = 0;
02599  
02600             to = ast_tvdiff_ms(nexteventts, now);
02601             if (to < 0) {
02602                to = 0;
02603             }
02604             time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
02605             if (time_left_ms < to) {
02606                to = time_left_ms;
02607             }
02608    
02609             if (time_left_ms <= 0) {
02610                if (user->end_sound) {                 
02611                   res = ast_streamfile(chan, user->end_sound, chan->language);
02612                   res = ast_waitstream(chan, "");
02613                }
02614                break;
02615             }
02616             
02617             if (!to) {
02618                if (time_left_ms >= 5000) {                  
02619                   
02620                   remain = (time_left_ms + 500) / 1000;
02621                   if (remain / 60 >= 1) {
02622                      minutes = remain / 60;
02623                      seconds = remain % 60;
02624                   } else {
02625                      seconds = remain;
02626                   }
02627                   
02628                   /* force the time left to round up if appropriate */
02629                   if (user->warning_sound && user->play_warning) {
02630                      if (!strcmp(user->warning_sound, "timeleft")) {
02631                         
02632                         res = ast_streamfile(chan, "vm-youhave", chan->language);
02633                         res = ast_waitstream(chan, "");
02634                         if (minutes) {
02635                            res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL);
02636                            res = ast_streamfile(chan, "queue-minutes", chan->language);
02637                            res = ast_waitstream(chan, "");
02638                         }
02639                         if (seconds) {
02640                            res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL);
02641                            res = ast_streamfile(chan, "queue-seconds", chan->language);
02642                            res = ast_waitstream(chan, "");
02643                         }
02644                      } else {
02645                         res = ast_streamfile(chan, user->warning_sound, chan->language);
02646                         res = ast_waitstream(chan, "");
02647                      }
02648                   }
02649                }
02650                if (user->warning_freq) {
02651                   nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
02652                } else {
02653                   nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
02654                }
02655             }
02656          }
02657 
02658          now = ast_tvnow();
02659          if (timeout && now.tv_sec >= timeout) {
02660             break;
02661          }
02662 
02663          /* if we have just exited from the menu, and the user had a channel-driver
02664             volume adjustment, restore it
02665          */
02666          if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual) {
02667             set_talk_volume(user, user->listen.desired);
02668          }
02669 
02670          menu_was_active = menu_active;
02671 
02672          currentmarked = conf->markedusers;
02673          if (!(confflags & CONFFLAG_QUIET) &&
02674              (confflags & CONFFLAG_MARKEDUSER) &&
02675              (confflags & CONFFLAG_WAITMARKED) &&
02676              lastmarked == 0) {
02677             if (currentmarked == 1 && conf->users > 1) {
02678                ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
02679                if (conf->users - 1 == 1) {
02680                   if (!ast_streamfile(chan, "conf-userwilljoin", chan->language)) {
02681                      ast_waitstream(chan, "");
02682                   }
02683                } else {
02684                   if (!ast_streamfile(chan, "conf-userswilljoin", chan->language)) {
02685                      ast_waitstream(chan, "");
02686                   }
02687                }
02688             }
02689             if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER)) {
02690                if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) {
02691                   ast_waitstream(chan, "");
02692                }
02693             }
02694          }
02695 
02696          /* Update the struct with the actual confflags */
02697          user->userflags = confflags;
02698 
02699          if (confflags & CONFFLAG_WAITMARKED) {
02700             if (currentmarked == 0) {
02701                if (lastmarked != 0) {
02702                   if (!(confflags & CONFFLAG_QUIET)) {
02703                      if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language)) {
02704                         ast_waitstream(chan, "");
02705                      }
02706                   }
02707                   if (confflags & CONFFLAG_MARKEDEXIT) {
02708                      if (confflags & CONFFLAG_KICK_CONTINUE) {
02709                         ret = 0;
02710                      }
02711                      break;
02712                   } else {
02713                      dahdic.confmode = DAHDI_CONF_CONF;
02714                      if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02715                         ast_log(LOG_WARNING, "Error setting conference\n");
02716                         close(fd);
02717                         goto outrun;
02718                      }
02719                   }
02720                }
02721                if (!musiconhold && (confflags & CONFFLAG_MOH)) {
02722                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02723                   musiconhold = 1;
02724                }
02725             } else if (currentmarked >= 1 && lastmarked == 0) {
02726                /* Marked user entered, so cancel timeout */
02727                timeout = 0;
02728                if (confflags & CONFFLAG_MONITOR) {
02729                   dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02730                } else if (confflags & CONFFLAG_TALKER) {
02731                   dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02732                } else {
02733                   dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02734                }
02735                if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02736                   ast_log(LOG_WARNING, "Error setting conference\n");
02737                   close(fd);
02738                   goto outrun;
02739                }
02740                if (musiconhold && (confflags & CONFFLAG_MOH)) {
02741                   ast_moh_stop(chan);
02742                   musiconhold = 0;
02743                }
02744                if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
02745                   if (!ast_streamfile(chan, "conf-placeintoconf", chan->language)) {
02746                      ast_waitstream(chan, "");
02747                   }
02748                   conf_play(chan, conf, ENTER);
02749                }
02750             }
02751          }
02752 
02753          /* trying to add moh for single person conf */
02754          if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
02755             if (conf->users == 1) {
02756                if (!musiconhold) {
02757                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02758                   musiconhold = 1;
02759                } 
02760             } else {
02761                if (musiconhold) {
02762                   ast_moh_stop(chan);
02763                   musiconhold = 0;
02764                }
02765             }
02766          }
02767          
02768          /* Leave if the last marked user left */
02769          if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
02770             if (confflags & CONFFLAG_KICK_CONTINUE) {
02771                ret = 0;
02772             } else {
02773                ret = -1;
02774             }
02775             break;
02776          }
02777    
02778          /* Check if my modes have changed */
02779 
02780          /* If I should be muted but am still talker, mute me */
02781          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
02782             dahdic.confmode ^= DAHDI_CONF_TALKER;
02783             if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02784                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02785                ret = -1;
02786                break;
02787             }
02788 
02789             /* Indicate user is not talking anymore - change him to unmonitored state */
02790             if ((confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) {
02791                set_user_talking(chan, conf, user, -1, confflags & CONFFLAG_MONITORTALKER);
02792             }
02793 
02794             manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
02795                   "Channel: %s\r\n"
02796                   "Uniqueid: %s\r\n"
02797                   "Meetme: %s\r\n"
02798                   "Usernum: %i\r\n"
02799                   "Status: on\r\n",
02800                   chan->name, chan->uniqueid, conf->confno, user->user_no);
02801          }
02802 
02803          /* If I should be un-muted but am not talker, un-mute me */
02804          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
02805             dahdic.confmode |= DAHDI_CONF_TALKER;
02806             if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02807                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02808                ret = -1;
02809                break;
02810             }
02811 
02812             manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
02813                   "Channel: %s\r\n"
02814                   "Uniqueid: %s\r\n"
02815                   "Meetme: %s\r\n"
02816                   "Usernum: %i\r\n"
02817                   "Status: off\r\n",
02818                   chan->name, chan->uniqueid, conf->confno, user->user_no);
02819          }
02820          
02821          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
02822             (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
02823             talkreq_manager = 1;
02824 
02825             manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 
02826                      "Channel: %s\r\n"
02827                            "Uniqueid: %s\r\n"
02828                            "Meetme: %s\r\n"
02829                            "Usernum: %i\r\n"
02830                            "Status: on\r\n",
02831                            chan->name, chan->uniqueid, conf->confno, user->user_no);
02832          }
02833 
02834          
02835          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
02836             !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
02837             talkreq_manager = 0;
02838             manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 
02839                      "Channel: %s\r\n"
02840                            "Uniqueid: %s\r\n"
02841                            "Meetme: %s\r\n"
02842                            "Usernum: %i\r\n"
02843                            "Status: off\r\n",
02844                           chan->name, chan->uniqueid, conf->confno, user->user_no);
02845          }
02846          
02847          /* If I have been kicked, exit the conference */
02848          if (user->adminflags & ADMINFLAG_KICKME) {
02849             /* You have been kicked. */
02850             if (!(confflags & CONFFLAG_QUIET) && 
02851                !ast_streamfile(chan, "conf-kicked", chan->language)) {
02852                ast_waitstream(chan, "");
02853             }
02854             ret = 0;
02855             break;
02856          }
02857 
02858          /* Perform an extra hangup check just in case */
02859          if (ast_check_hangup(chan)) {
02860             break;
02861          }
02862 
02863          c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
02864 
02865          if (c) {
02866             char dtmfstr[2] = "";
02867 
02868             if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) {
02869                if (using_pseudo) {
02870                   /* Kill old pseudo */
02871                   close(fd);
02872                   using_pseudo = 0;
02873                }
02874                ast_debug(1, "Ooh, something swapped out under us, starting over\n");
02875                retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0);
02876                user->dahdichannel = !retrydahdi;
02877                goto dahdiretry;
02878             }
02879             if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02880                f = ast_read_noaudio(c);
02881             } else {
02882                f = ast_read(c);
02883             }
02884             if (!f) {
02885                break;
02886             }
02887             if (f->frametype == AST_FRAME_DTMF) {
02888                dtmfstr[0] = f->subclass;
02889                dtmfstr[1] = '\0';
02890             }
02891 
02892             if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
02893                if (user->talk.actual) {
02894                   ast_frame_adjust_volume(f, user->talk.actual);
02895                }
02896 
02897                if (confflags & (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER)) {
02898                   if (user->talking == -1) {
02899                      user->talking = 0;
02900                   }
02901 
02902                   res = ast_dsp_silence(dsp, f, &totalsilence);
02903                   if (totalsilence < MEETME_DELAYDETECTTALK) {
02904                      set_user_talking(chan, conf, user, 1, confflags & CONFFLAG_MONITORTALKER);
02905                   }
02906                   if (totalsilence > MEETME_DELAYDETECTENDTALK) {
02907                      set_user_talking(chan, conf, user, 0, confflags & CONFFLAG_MONITORTALKER);
02908                   }
02909                }
02910                if (using_pseudo) {
02911                   /* Absolutely do _not_ use careful_write here...
02912                      it is important that we read data from the channel
02913                      as fast as it arrives, and feed it into the conference.
02914                      The buffering in the pseudo channel will take care of any
02915                      timing differences, unless they are so drastic as to lose
02916                      audio frames (in which case carefully writing would only
02917                      have delayed the audio even further).
02918                   */
02919                   /* As it turns out, we do want to use careful write.  We just
02920                      don't want to block, but we do want to at least *try*
02921                      to write out all the samples.
02922                    */
02923                   if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER)) {
02924                      careful_write(fd, f->data.ptr, f->datalen, 0);
02925                   }
02926                }
02927             } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
02928                if (confflags & CONFFLAG_PASS_DTMF) {
02929                   conf_queue_dtmf(conf, user, f);
02930                }
02931                if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
02932                   ast_log(LOG_WARNING, "Error setting conference\n");
02933                   close(fd);
02934                   ast_frfree(f);
02935                   goto outrun;
02936                }
02937 
02938                /* if we are entering the menu, and the user has a channel-driver
02939                   volume adjustment, clear it
02940                */
02941                if (!menu_active && user->talk.desired && !user->talk.actual) {
02942                   set_talk_volume(user, 0);
02943                }
02944 
02945                if (musiconhold) {
02946                      ast_moh_stop(chan);
02947                }
02948                if ((confflags & CONFFLAG_ADMIN)) {
02949                   /* Admin menu */
02950                   if (!menu_active) {
02951                      menu_active = 1;
02952                      /* Record this sound! */
02953                      if (!ast_streamfile(chan, "conf-adminmenu-162", chan->language)) {
02954                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02955                         ast_stopstream(chan);
02956                      } else {
02957                         dtmf = 0;
02958                      }
02959                   } else {
02960                      dtmf = f->subclass;
02961                   }
02962                   if (dtmf) {
02963                      switch(dtmf) {
02964                      case '1': /* Un/Mute */
02965                         menu_active = 0;
02966 
02967                         /* for admin, change both admin and use flags */
02968                         if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
02969                            user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02970                         } else {
02971                            user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02972                         }
02973 
02974                         if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02975                            if (!ast_streamfile(chan, "conf-muted", chan->language)) {
02976                               ast_waitstream(chan, "");
02977                            }
02978                         } else {
02979                            if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
02980                               ast_waitstream(chan, "");
02981                            }
02982                         }
02983                         break;
02984                      case '2': /* Un/Lock the Conference */
02985                         menu_active = 0;
02986                         if (conf->locked) {
02987                            conf->locked = 0;
02988                            if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) {
02989                               ast_waitstream(chan, "");
02990                            }
02991                         } else {
02992                            conf->locked = 1;
02993                            if (!ast_streamfile(chan, "conf-lockednow", chan->language)) {
02994                               ast_waitstream(chan, "");
02995                            }
02996                         }
02997                         break;
02998                      case '3': /* Eject last user */
02999                         menu_active = 0;
03000                         usr = AST_LIST_LAST(&conf->userlist);
03001                         if ((usr->chan->name == chan->name) || (usr->userflags & CONFFLAG_ADMIN)) {
03002                            if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
03003                               ast_waitstream(chan, "");
03004                            }
03005                         } else {
03006                            usr->adminflags |= ADMINFLAG_KICKME;
03007                         }
03008                         ast_stopstream(chan);
03009                         break;   
03010                      case '4':
03011                         tweak_listen_volume(user, VOL_DOWN);
03012                         break;
03013                      case '5':
03014                         /* Extend RT conference */
03015                         if (rt_schedule) {
03016                            if (!rt_extend_conf(conf->confno)) {
03017                               if (!ast_streamfile(chan, "conf-extended", chan->language)) {
03018                                  ast_waitstream(chan, "");
03019                               }
03020                            } else {
03021                               if (!ast_streamfile(chan, "conf-nonextended", chan->language)) {
03022                                  ast_waitstream(chan, "");
03023                               }
03024                            }
03025                            ast_stopstream(chan);
03026                         }
03027                         menu_active = 0;
03028                         break;
03029                      case '6':
03030                         tweak_listen_volume(user, VOL_UP);
03031                         break;
03032                      case '7':
03033                         tweak_talk_volume(user, VOL_DOWN);
03034                         break;
03035                      case '8':
03036                         menu_active = 0;
03037                         break;
03038                      case '9':
03039                         tweak_talk_volume(user, VOL_UP);
03040                         break;
03041                      default:
03042                         menu_active = 0;
03043                         /* Play an error message! */
03044                         if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
03045                            ast_waitstream(chan, "");
03046                         }
03047                         break;
03048                      }
03049                   }
03050                } else {
03051                   /* User menu */
03052                   if (!menu_active) {
03053                      menu_active = 1;
03054                      if (!ast_streamfile(chan, "conf-usermenu-162", chan->language)) {
03055                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
03056                         ast_stopstream(chan);
03057                      } else {
03058                         dtmf = 0;
03059                      }
03060                   } else {
03061                      dtmf = f->subclass;
03062                   }
03063                   if (dtmf) {
03064                      switch (dtmf) {
03065                      case '1': /* Un/Mute */
03066                         menu_active = 0;
03067 
03068                         /* user can only toggle the self-muted state */
03069                         user->adminflags ^= ADMINFLAG_SELFMUTED;
03070 
03071                         /* they can't override the admin mute state */
03072                         if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
03073                            if (!ast_streamfile(chan, "conf-muted", chan->language)) {
03074                               ast_waitstream(chan, "");
03075                            }
03076                         } else {
03077                            if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
03078                               ast_waitstream(chan, "");
03079                            }
03080                         }
03081                         break;
03082                      case '2':
03083                         menu_active = 0;
03084                         if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
03085                            user->adminflags |= ADMINFLAG_T_REQUEST;
03086                         }
03087                            
03088                         if (user->adminflags & ADMINFLAG_T_REQUEST) {
03089                            if (!ast_streamfile(chan, "beep", chan->language)) {
03090                               ast_waitstream(chan, "");
03091                            }
03092                         }
03093                         break;
03094                      case '4':
03095                         tweak_listen_volume(user, VOL_DOWN);
03096                         break;
03097                      case '5':
03098                         /* Extend RT conference */
03099                         if (rt_schedule) {
03100                            rt_extend_conf(conf->confno);
03101                         }
03102                         menu_active = 0;
03103                         break;
03104                      case '6':
03105                         tweak_listen_volume(user, VOL_UP);
03106                         break;
03107                      case '7':
03108                         tweak_talk_volume(user, VOL_DOWN);
03109                         break;
03110                      case '8':
03111                         menu_active = 0;
03112                         break;
03113                      case '9':
03114                         tweak_talk_volume(user, VOL_UP);
03115                         break;
03116                      default:
03117                         menu_active = 0;
03118                         if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
03119                            ast_waitstream(chan, "");
03120                         }
03121                         break;
03122                      }
03123                   }
03124                }
03125                if (musiconhold) {
03126                   conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03127                }
03128 
03129                if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03130                   ast_log(LOG_WARNING, "Error setting conference\n");
03131                   close(fd);
03132                   ast_frfree(f);
03133                   goto outrun;
03134                }
03135 
03136                conf_flush(fd, chan);
03137             /* Since this option could absorb DTMF meant for the previous (menu), we have to check this one last */
03138             } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
03139                if (confflags & CONFFLAG_PASS_DTMF) {
03140                   conf_queue_dtmf(conf, user, f);
03141                }
03142 
03143                if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
03144                   ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
03145                   ret = 0;
03146                   ast_frfree(f);
03147                   break;
03148                } else {
03149                   ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
03150                }
03151             } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) {
03152                pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
03153                   
03154                if (confflags & CONFFLAG_PASS_DTMF) {
03155                   conf_queue_dtmf(conf, user, f);
03156                }
03157                ret = 0;
03158                ast_frfree(f);
03159                break;
03160             } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
03161                && confflags & CONFFLAG_PASS_DTMF) {
03162                conf_queue_dtmf(conf, user, f);
03163             } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
03164                switch (f->subclass) {
03165                case AST_CONTROL_HOLD:
03166                   sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
03167                   break;
03168                default:
03169                   break;
03170                }
03171             } else if (f->frametype == AST_FRAME_NULL) {
03172                /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
03173             } else {
03174                ast_debug(1, 
03175                   "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
03176                   chan->name, f->frametype, f->subclass);
03177             }
03178             ast_frfree(f);
03179          } else if (outfd > -1) {
03180             res = read(outfd, buf, CONF_SIZE);
03181             if (res > 0) {
03182                memset(&fr, 0, sizeof(fr));
03183                fr.frametype = AST_FRAME_VOICE;
03184                fr.subclass = AST_FORMAT_SLINEAR;
03185                fr.datalen = res;
03186                fr.samples = res / 2;
03187                fr.data.ptr = buf;
03188                fr.offset = AST_FRIENDLY_OFFSET;
03189                if (!user->listen.actual &&
03190                   ((confflags & CONFFLAG_MONITOR) ||
03191                    (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
03192                    (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
03193                    )) {
03194                   int idx;
03195                   for (idx = 0; idx < AST_FRAME_BITS; idx++) {
03196                      if (chan->rawwriteformat & (1 << idx)) {
03197                         break;
03198                      }
03199                   }
03200                   if (idx >= AST_FRAME_BITS) {
03201                      goto bailoutandtrynormal;
03202                   }
03203                   ast_mutex_lock(&conf->listenlock);
03204                   if (!conf->transframe[idx]) {
03205                      if (conf->origframe) {
03206                         if (!conf->transpath[idx]) {
03207                            conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR);
03208                         }
03209                         if (conf->transpath[idx]) {
03210                            conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
03211                            if (!conf->transframe[idx]) {
03212                               conf->transframe[idx] = &ast_null_frame;
03213                            }
03214                         }
03215                      }
03216                   }
03217                   if (conf->transframe[idx]) {
03218                      if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
03219                          can_write(chan, confflags)) {
03220                         struct ast_frame *cur;
03221                         if (musiconhold && !ast_dsp_silence(dsp, conf->transframe[idx], &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
03222                            ast_moh_stop(chan);
03223                            mohtempstopped = 1;
03224                         }
03225 
03226                         /* the translator may have returned a list of frames, so
03227                            write each one onto the channel
03228                         */
03229                         for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
03230                            if (ast_write(chan, cur)) {
03231                               ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
03232                               break;
03233                            }
03234                         }
03235                         if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
03236                            mohtempstopped = 0;
03237                            ast_moh_start(chan, NULL, NULL);
03238                         }
03239                      }
03240                   } else {
03241                      ast_mutex_unlock(&conf->listenlock);
03242                      goto bailoutandtrynormal;
03243                   }
03244                   ast_mutex_unlock(&conf->listenlock);
03245                } else {
03246 bailoutandtrynormal:
03247                   if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
03248                      ast_moh_stop(chan);
03249                      mohtempstopped = 1;
03250                   }
03251                   if (user->listen.actual) {
03252                      ast_frame_adjust_volume(&fr, user->listen.actual);
03253                   }
03254                   if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
03255                      ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
03256                   }
03257                   if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
03258                      mohtempstopped = 0;
03259                      ast_moh_start(chan, NULL, NULL);
03260                   }
03261                }
03262             } else {
03263                ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
03264             }
03265          }
03266          lastmarked = currentmarked;
03267       }
03268    }
03269 
03270    if (musiconhold) {
03271       ast_moh_stop(chan);
03272    }
03273    
03274    if (using_pseudo) {
03275       close(fd);
03276    } else {
03277       /* Take out of conference */
03278       dahdic.chan = 0;  
03279       dahdic.confno = 0;
03280       dahdic.confmode = 0;
03281       if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03282          ast_log(LOG_WARNING, "Error setting conference\n");
03283       }
03284    }
03285 
03286    reset_volumes(user);
03287 
03288    if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
03289       conf_play(chan, conf, LEAVE);
03290    }
03291 
03292    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
03293       struct announce_listitem *item;
03294       if (!(item = ao2_alloc(sizeof(*item), NULL)))
03295          return -1;
03296       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
03297       ast_copy_string(item->language, chan->language, sizeof(item->language));
03298       item->confchan = conf->chan;
03299       item->confusers = conf->users;
03300       item->announcetype = CONF_HASLEFT;
03301       ast_mutex_lock(&conf->announcelistlock);
03302       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
03303       ast_cond_signal(&conf->announcelist_addition);
03304       ast_mutex_unlock(&conf->announcelistlock);
03305    } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) {
03306       /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
03307       ast_filedelete(user->namerecloc, NULL);
03308    }
03309 
03310  outrun:
03311    AST_LIST_LOCK(&confs);
03312 
03313    if (dsp) {
03314       ast_dsp_free(dsp);
03315    }
03316    
03317    if (user->user_no) { /* Only cleanup users who really joined! */
03318       now = ast_tvnow();
03319       hr = (now.tv_sec - user->jointime) / 3600;
03320       min = ((now.tv_sec - user->jointime) % 3600) / 60;
03321       sec = (now.tv_sec - user->jointime) % 60;
03322 
03323       if (sent_event) {
03324          manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
03325                   "Channel: %s\r\n"
03326                   "Uniqueid: %s\r\n"
03327                   "Meetme: %s\r\n"
03328                   "Usernum: %d\r\n"
03329                   "CallerIDNum: %s\r\n"
03330                   "CallerIDName: %s\r\n"
03331                   "Duration: %ld\r\n",
03332                   chan->name, chan->uniqueid, conf->confno, 
03333                   user->user_no,
03334                   S_OR(user->chan->cid.cid_num, "<unknown>"),
03335                   S_OR(user->chan->cid.cid_name, "<unknown>"),
03336                   (long)(now.tv_sec - user->jointime));
03337       }
03338 
03339       if (setusercount) {
03340          conf->users--;
03341          if (rt_log_members) {
03342             /* Update table */
03343             snprintf(members, sizeof(members), "%d", conf->users);
03344             ast_realtime_require_field("meetme",
03345                "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
03346                "members", RQ_UINTEGER1, strlen(members),
03347                NULL);
03348             ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
03349          }
03350          if (confflags & CONFFLAG_MARKEDUSER) {
03351             conf->markedusers--;
03352          }
03353       }
03354       /* Remove ourselves from the list */
03355       AST_LIST_REMOVE(&conf->userlist, user, list);
03356 
03357       /* Change any states */
03358       if (!conf->users) {
03359          ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
03360       }
03361 
03362       /* Return the number of seconds the user was in the conf */
03363       snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
03364       pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
03365    }
03366    ast_free(user);
03367    AST_LIST_UNLOCK(&confs);
03368 
03369    return ret;
03370 }

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

Definition at line 1877 of file app_meetme.c.

References ast_channel_lock, ast_channel_unlock, ast_moh_start(), ast_string_field_set, and ast_channel::musicclass.

Referenced by conf_run().

01878 {
01879    char *original_moh;
01880 
01881    ast_channel_lock(chan);
01882    original_moh = ast_strdupa(chan->musicclass);
01883    ast_string_field_set(chan, musicclass, musicclass);
01884    ast_channel_unlock(chan);
01885 
01886    ast_moh_start(chan, original_moh, NULL);
01887 
01888    ast_channel_lock(chan);
01889    ast_string_field_set(chan, musicclass, original_moh);
01890    ast_channel_unlock(chan);
01891 }

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

The MeetmeCount application.

Definition at line 3650 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_strlen_zero(), dispose_conf(), find_conf(), ast_channel::language, LOG_WARNING, pbx_builtin_setvar_helper(), and ast_conference::users.

Referenced by load_module().

03651 {
03652    int res = 0;
03653    struct ast_conference *conf;
03654    int count;
03655    char *localdata;
03656    char val[80] = "0"; 
03657    AST_DECLARE_APP_ARGS(args,
03658       AST_APP_ARG(confno);
03659       AST_APP_ARG(varname);
03660    );
03661 
03662    if (ast_strlen_zero(data)) {
03663       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
03664       return -1;
03665    }
03666    
03667    if (!(localdata = ast_strdupa(data)))
03668       return -1;
03669 
03670    AST_STANDARD_APP_ARGS(args, localdata);
03671    
03672    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
03673 
03674    if (conf) {
03675       count = conf->users;
03676       dispose_conf(conf);
03677       conf = NULL;
03678    } else
03679       count = 0;
03680 
03681    if (!ast_strlen_zero(args.varname)) {
03682       /* have var so load it and exit */
03683       snprintf(val, sizeof(val), "%d", count);
03684       pbx_builtin_setvar_helper(chan, args.varname, val);
03685    } else {
03686       if (chan->_state != AST_STATE_UP) {
03687          ast_answer(chan);
03688       }
03689       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
03690    }
03691 
03692    return res;
03693 }

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

Definition at line 5762 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

05763 {
05764    struct sla_trunk_ref *trunk_ref;
05765 
05766    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
05767       return NULL;
05768 
05769    trunk_ref->trunk = trunk;
05770 
05771    return trunk_ref;
05772 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 5973 of file app_meetme.c.

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

Referenced by sla_build_station(), and sla_destroy().

05974 {
05975    struct sla_trunk_ref *trunk_ref;
05976 
05977    if (!ast_strlen_zero(station->autocontext)) {
05978       AST_RWLIST_RDLOCK(&sla_trunks);
05979       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05980          char exten[AST_MAX_EXTENSION];
05981          char hint[AST_MAX_APP];
05982          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05983          snprintf(hint, sizeof(hint), "SLA:%s", exten);
05984          ast_context_remove_extension(station->autocontext, exten, 
05985             1, sla_registrar);
05986          ast_context_remove_extension(station->autocontext, hint, 
05987             PRIORITY_HINT, sla_registrar);
05988       }
05989       AST_RWLIST_UNLOCK(&sla_trunks);
05990    }
05991 
05992    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
05993       ast_free(trunk_ref);
05994 
05995    ast_string_field_free_memory(station);
05996    ast_free(station);
05997 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 5959 of file app_meetme.c.

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

Referenced by sla_build_trunk(), and sla_destroy().

05960 {
05961    struct sla_station_ref *station_ref;
05962 
05963    if (!ast_strlen_zero(trunk->autocontext))
05964       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
05965 
05966    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
05967       ast_free(station_ref);
05968 
05969    ast_string_field_free_memory(trunk);
05970    ast_free(trunk);
05971 }

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

Definition at line 5474 of file app_meetme.c.

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

Referenced by sla_station_exec().

05475 {
05476    struct dial_trunk_args *args = data;
05477    struct ast_dial *dial;
05478    char *tech, *tech_data;
05479    enum ast_dial_result dial_res;
05480    char conf_name[MAX_CONFNUM];
05481    struct ast_conference *conf;
05482    struct ast_flags conf_flags = { 0 };
05483    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
05484    const char *cid_name = NULL, *cid_num = NULL;
05485 
05486    if (!(dial = ast_dial_create())) {
05487       ast_mutex_lock(args->cond_lock);
05488       ast_cond_signal(args->cond);
05489       ast_mutex_unlock(args->cond_lock);
05490       return NULL;
05491    }
05492 
05493    tech_data = ast_strdupa(trunk_ref->trunk->device);
05494    tech = strsep(&tech_data, "/");
05495    if (ast_dial_append(dial, tech, tech_data) == -1) {
05496       ast_mutex_lock(args->cond_lock);
05497       ast_cond_signal(args->cond);
05498       ast_mutex_unlock(args->cond_lock);
05499       ast_dial_destroy(dial);
05500       return NULL;
05501    }
05502 
05503    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
05504       cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
05505       ast_free(trunk_ref->chan->cid.cid_name);
05506       trunk_ref->chan->cid.cid_name = NULL;
05507    }
05508    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
05509       cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
05510       ast_free(trunk_ref->chan->cid.cid_num);
05511       trunk_ref->chan->cid.cid_num = NULL;
05512    }
05513 
05514    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
05515 
05516    if (cid_name)
05517       trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
05518    if (cid_num)
05519       trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
05520 
05521    if (dial_res != AST_DIAL_RESULT_TRYING) {
05522       ast_mutex_lock(args->cond_lock);
05523       ast_cond_signal(args->cond);
05524       ast_mutex_unlock(args->cond_lock);
05525       ast_dial_destroy(dial);
05526       return NULL;
05527    }
05528 
05529    for (;;) {
05530       unsigned int done = 0;
05531       switch ((dial_res = ast_dial_state(dial))) {
05532       case AST_DIAL_RESULT_ANSWERED:
05533          trunk_ref->trunk->chan = ast_dial_answered(dial);
05534       case AST_DIAL_RESULT_HANGUP:
05535       case AST_DIAL_RESULT_INVALID:
05536       case AST_DIAL_RESULT_FAILED:
05537       case AST_DIAL_RESULT_TIMEOUT:
05538       case AST_DIAL_RESULT_UNANSWERED:
05539          done = 1;
05540       case AST_DIAL_RESULT_TRYING:
05541       case AST_DIAL_RESULT_RINGING:
05542       case AST_DIAL_RESULT_PROGRESS:
05543       case AST_DIAL_RESULT_PROCEEDING:
05544          break;
05545       }
05546       if (done)
05547          break;
05548    }
05549 
05550    if (!trunk_ref->trunk->chan) {
05551       ast_mutex_lock(args->cond_lock);
05552       ast_cond_signal(args->cond);
05553       ast_mutex_unlock(args->cond_lock);
05554       ast_dial_join(dial);
05555       ast_dial_destroy(dial);
05556       return NULL;
05557    }
05558 
05559    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05560    ast_set_flag(&conf_flags, 
05561       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
05562       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
05563    conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan);
05564 
05565    ast_mutex_lock(args->cond_lock);
05566    ast_cond_signal(args->cond);
05567    ast_mutex_unlock(args->cond_lock);
05568 
05569    if (conf) {
05570       conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
05571       dispose_conf(conf);
05572       conf = NULL;
05573    }
05574 
05575    /* If the trunk is going away, it is definitely now IDLE. */
05576    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05577 
05578    trunk_ref->trunk->chan = NULL;
05579    trunk_ref->trunk->on_hold = 0;
05580 
05581    ast_dial_join(dial);
05582    ast_dial_destroy(dial);
05583 
05584    return NULL;
05585 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Definition at line 1796 of file app_meetme.c.

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

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

01797 {
01798    int res = 0;
01799    int confno_int = 0;
01800 
01801    AST_LIST_LOCK(&confs);
01802    if (ast_atomic_dec_and_test(&conf->refcount)) {
01803       /* Take the conference room number out of an inuse state */
01804       if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
01805          conf_map[confno_int] = 0;
01806       }
01807       conf_free(conf);
01808       res = 1;
01809    }
01810    AST_LIST_UNLOCK(&confs);
01811 
01812    return res;
01813 }

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

Definition at line 3546 of file app_meetme.c.

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

Referenced by conf_exec(), and count_exec().

03548 {
03549    struct ast_config *cfg;
03550    struct ast_variable *var;
03551    struct ast_flags config_flags = { 0 };
03552    struct ast_conference *cnf;
03553 
03554    AST_DECLARE_APP_ARGS(args,
03555       AST_APP_ARG(confno);
03556       AST_APP_ARG(pin);
03557       AST_APP_ARG(pinadmin);
03558    );
03559 
03560    /* Check first in the conference list */
03561    ast_debug(1, "The requested confno is '%s'?\n", confno);
03562    AST_LIST_LOCK(&confs);
03563    AST_LIST_TRAVERSE(&confs, cnf, list) {
03564       ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
03565       if (!strcmp(confno, cnf->confno)) 
03566          break;
03567    }
03568    if (cnf) {
03569       cnf->refcount += refcount;
03570    }
03571    AST_LIST_UNLOCK(&confs);
03572 
03573    if (!cnf) {
03574       if (dynamic) {
03575          /* No need to parse meetme.conf */
03576          ast_debug(1, "Building dynamic conference '%s'\n", confno);
03577          if (dynamic_pin) {
03578             if (dynamic_pin[0] == 'q') {
03579                /* Query the user to enter a PIN */
03580                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
03581                   return NULL;
03582             }
03583             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
03584          } else {
03585             cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
03586          }
03587       } else {
03588          /* Check the config */
03589          cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03590          if (!cfg) {
03591             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
03592             return NULL;
03593          } else if (cfg == CONFIG_STATUS_FILEINVALID) {
03594             ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
03595             return NULL;
03596          }
03597 
03598          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
03599             char parse[MAX_SETTINGS];
03600 
03601             if (strcasecmp(var->name, "conf"))
03602                continue;
03603 
03604             ast_copy_string(parse, var->value, sizeof(parse));
03605 
03606             AST_STANDARD_APP_ARGS(args, parse);
03607             ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
03608             if (!strcasecmp(args.confno, confno)) {
03609                /* Bingo it's a valid conference */
03610                cnf = build_conf(args.confno,
03611                      S_OR(args.pin, ""),
03612                      S_OR(args.pinadmin, ""),
03613                      make, dynamic, refcount, chan);
03614                break;
03615             }
03616          }
03617          if (!var) {
03618             ast_debug(1, "%s isn't a valid conference\n", confno);
03619          }
03620          ast_config_destroy(cfg);
03621       }
03622    } else if (dynamic_pin) {
03623       /* Correct for the user selecting 'D' instead of 'd' to have
03624          someone join into a conference that has already been created
03625          with a pin. */
03626       if (dynamic_pin[0] == 'q') {
03627          dynamic_pin[0] = '\0';
03628       }
03629    }
03630 
03631    if (cnf) {
03632       if (confflags && !cnf->chan &&
03633           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03634           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03635          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03636          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03637       }
03638       
03639       if (confflags && !cnf->chan &&
03640           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03641          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03642          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03643       }
03644    }
03645 
03646    return cnf;
03647 }

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

Definition at line 3372 of file app_meetme.c.

References ast_conference::adminopts, ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_copy_string(), ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log(), AST_MAX_EXTENSION, ast_mktime(), ast_strdup, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_test_flag, ast_tvnow(), ast_variables_destroy(), ast_verb, ast_waitstream(), ast_conference::bookid, build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, ast_conference::confno, DATE_FORMAT, ast_conference::endalert, ast_conference::endtime, ast_channel::language, ast_conference::list, LOG_WARNING, ast_conference::maxusers, ast_variable::name, ast_variable::next, OPTIONS_LEN, pbx_builtin_getvar_helper(), ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::refcount, ast_channel::uniqueid, ast_conference::useropts, ast_variable::value, and var.

Referenced by conf_exec().

03374 {
03375    struct ast_variable *var, *origvar;
03376    struct ast_conference *cnf;
03377 
03378    *too_early = 0;
03379 
03380    /* Check first in the conference list */
03381    AST_LIST_LOCK(&confs);
03382    AST_LIST_TRAVERSE(&confs, cnf, list) {
03383       if (!strcmp(confno, cnf->confno)) 
03384          break;
03385    }
03386    if (cnf) {
03387       cnf->refcount += refcount;
03388    }
03389    AST_LIST_UNLOCK(&confs);
03390 
03391    if (!cnf) {
03392       char *pin = NULL, *pinadmin = NULL; /* For temp use */
03393       int maxusers = 0;
03394       struct timeval now;
03395       char recordingfilename[256] = "";
03396       char recordingformat[11] = "";
03397       char currenttime[19] = "";
03398       char eatime[19] = "";
03399       char bookid[51] = "";
03400       char recordingtmp[AST_MAX_EXTENSION] = "";
03401       char useropts[OPTIONS_LEN + 1]; /* Used for RealTime conferences */
03402       char adminopts[OPTIONS_LEN + 1];
03403       struct ast_tm tm, etm;
03404       struct timeval endtime = { .tv_sec = 0 };
03405       const char *var2;
03406 
03407       if (rt_schedule) {
03408          now = ast_tvnow();
03409 
03410          ast_localtime(&now, &tm, NULL);
03411          ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03412 
03413          ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
03414 
03415          var = ast_load_realtime("meetme", "confno",
03416             confno, "starttime <= ", currenttime, "endtime >= ",
03417             currenttime, NULL);
03418 
03419          if (!var && fuzzystart) {
03420             now = ast_tvnow();
03421             now.tv_sec += fuzzystart;
03422 
03423             ast_localtime(&now, &tm, NULL);
03424             ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03425             var = ast_load_realtime("meetme", "confno",
03426                confno, "starttime <= ", currenttime, "endtime >= ",
03427                currenttime, NULL);
03428          }
03429 
03430          if (!var && earlyalert) {
03431             now = ast_tvnow();
03432             now.tv_sec += earlyalert;
03433             ast_localtime(&now, &etm, NULL);
03434             ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
03435             var = ast_load_realtime("meetme", "confno",
03436                confno, "starttime <= ", eatime, "endtime >= ",
03437                currenttime, NULL);
03438             if (var) {
03439                *too_early = 1;
03440             }
03441          }
03442 
03443       } else {
03444           var = ast_load_realtime("meetme", "confno", confno, NULL);
03445       }
03446 
03447       if (!var)
03448          return NULL;
03449 
03450       if (rt_schedule && *too_early) {
03451          /* Announce that the caller is early and exit */
03452          if (!ast_streamfile(chan, "conf-has-not-started", chan->language))
03453             ast_waitstream(chan, "");
03454          ast_variables_destroy(var);
03455          return NULL;
03456       }
03457 
03458       for (origvar = var; var; var = var->next) {
03459          if (!strcasecmp(var->name, "pin")) {
03460             pin = ast_strdupa(var->value);
03461          } else if (!strcasecmp(var->name, "adminpin")) {
03462             pinadmin = ast_strdupa(var->value);
03463          } else if (!strcasecmp(var->name, "bookId")) {
03464             ast_copy_string(bookid, var->value, sizeof(bookid));
03465          } else if (!strcasecmp(var->name, "opts")) {
03466             ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
03467          } else if (!strcasecmp(var->name, "maxusers")) {
03468             maxusers = atoi(var->value);
03469          } else if (!strcasecmp(var->name, "adminopts")) {
03470             ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
03471          } else if (!strcasecmp(var->name, "recordingfilename")) {
03472             ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
03473          } else if (!strcasecmp(var->name, "recordingformat")) {
03474             ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
03475          } else if (!strcasecmp(var->name, "endtime")) {
03476             struct ast_tm endtime_tm;
03477             ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
03478             endtime = ast_mktime(&endtime_tm, NULL);
03479          }
03480       }
03481 
03482       ast_variables_destroy(origvar);
03483 
03484       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
03485 
03486       if (cnf) {
03487          cnf->maxusers = maxusers;
03488          cnf->endalert = endalert;
03489          cnf->endtime = endtime.tv_sec;
03490          cnf->useropts = ast_strdup(useropts);
03491          cnf->adminopts = ast_strdup(adminopts);
03492          cnf->bookid = ast_strdup(bookid);
03493          cnf->recordingfilename = ast_strdup(recordingfilename);
03494          cnf->recordingformat = ast_strdup(recordingformat);
03495 
03496          if (strchr(cnf->useropts, 'r')) {
03497             if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */
03498                ast_channel_lock(chan);
03499                if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
03500                   ast_free(cnf->recordingfilename);
03501                   cnf->recordingfilename = ast_strdup(var2);
03502                }
03503                ast_channel_unlock(chan);
03504                if (ast_strlen_zero(cnf->recordingfilename)) {
03505                   snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, chan->uniqueid);
03506                   ast_free(cnf->recordingfilename);
03507                   cnf->recordingfilename = ast_strdup(recordingtmp);
03508                }
03509             }
03510             if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */
03511                ast_channel_lock(chan);
03512                if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
03513                   ast_free(cnf->recordingformat);
03514                   cnf->recordingformat = ast_strdup(var2);
03515                }
03516                ast_channel_unlock(chan);
03517                if (ast_strlen_zero(cnf->recordingformat)) {
03518                   ast_free(cnf->recordingformat);
03519                   cnf->recordingformat = ast_strdup("wav");
03520                }
03521             }
03522             ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
03523          }
03524       }
03525    }
03526 
03527    if (cnf) {
03528       if (confflags && !cnf->chan &&
03529           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03530           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03531          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03532          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03533       }
03534       
03535       if (confflags && !cnf->chan &&
03536           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03537          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03538          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03539       }
03540    }
03541 
03542    return cnf;
03543 }

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

Definition at line 3952 of file app_meetme.c.

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

Referenced by admin_exec().

03953 {
03954    struct ast_conf_user *user = NULL;
03955    int cid;
03956    
03957    sscanf(callerident, "%30i", &cid);
03958    if (conf && callerident) {
03959       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03960          if (cid == user->user_no)
03961             return user;
03962       }
03963    }
03964    return NULL;
03965 }

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

Definition at line 1893 of file app_meetme.c.

References CONF_HASJOIN, and CONF_HASLEFT.

Referenced by announce_thread().

01894 {
01895    switch (type) {
01896    case CONF_HASLEFT:
01897       return "conf-hasleft";
01898       break;
01899    case CONF_HASJOIN:
01900       return "conf-hasjoin";
01901       break;
01902    default:
01903       return "";
01904    }
01905 }

static char* istalking ( int  x  )  [static]

Definition at line 885 of file app_meetme.c.

Referenced by meetme_show_cmd().

00886 {
00887    if (x > 0)
00888       return "(talking)";
00889    else if (x < 0)
00890       return "(unmonitored)";
00891    else 
00892       return "(not talking)";
00893 }

static int load_config ( int  reload  )  [static]

Definition at line 6421 of file app_meetme.c.

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

Referenced by load_module(), and reload().

06422 {
06423    load_config_meetme();
06424 
06425    if (reload) {
06426       sla_queue_event(SLA_EVENT_RELOAD);
06427       ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
06428          "and will be completed when the system is idle.\n");
06429       return 0;
06430    }
06431    
06432    return sla_load_config(0);
06433 }

static void load_config_meetme ( void   )  [static]

Definition at line 4446 of file app_meetme.c.

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

Referenced by load_config().

04447 {
04448    struct ast_config *cfg;
04449    struct ast_flags config_flags = { 0 };
04450    const char *val;
04451 
04452    if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
04453       return;
04454    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04455       ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
04456       return;
04457    }
04458 
04459    audio_buffers = DEFAULT_AUDIO_BUFFERS;
04460 
04461    /*  Scheduling support is off by default */
04462    rt_schedule = 0;
04463    fuzzystart = 0;
04464    earlyalert = 0;
04465    endalert = 0;
04466    extendby = 0;
04467 
04468    /*  Logging of participants defaults to ON for compatibility reasons */
04469    rt_log_members = 1;  
04470 
04471    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
04472       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
04473          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
04474          audio_buffers = DEFAULT_AUDIO_BUFFERS;
04475       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
04476          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
04477             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
04478          audio_buffers = DEFAULT_AUDIO_BUFFERS;
04479       }
04480       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
04481          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
04482    }
04483 
04484    if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
04485       rt_schedule = ast_true(val);
04486    if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
04487       rt_log_members = ast_true(val);
04488    if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
04489       if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
04490          ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
04491          fuzzystart = 0;
04492       } 
04493    }
04494    if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
04495       if ((sscanf(val, "%30d", &earlyalert) != 1)) {
04496          ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
04497          earlyalert = 0;
04498       } 
04499    }
04500    if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
04501       if ((sscanf(val, "%30d", &endalert) != 1)) {
04502          ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
04503          endalert = 0;
04504       } 
04505    }
04506    if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
04507       if ((sscanf(val, "%30d", &extendby) != 1)) {
04508          ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
04509          extendby = 0;
04510       } 
04511    }
04512 
04513    ast_config_destroy(cfg);
04514 }

static int load_module ( void   )  [static]

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

06462 {
06463    int res = 0;
06464 
06465    res |= load_config(0);
06466 
06467    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
06468    res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 
06469                 action_meetmemute, "Mute a Meetme user");
06470    res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 
06471                 action_meetmeunmute, "Unmute a Meetme user");
06472    res |= ast_manager_register2("MeetmeList", EVENT_FLAG_REPORTING, 
06473                 action_meetmelist, "List participants in a conference", mandescr_meetmelist);
06474    res |= ast_register_application_xml(app4, channel_admin_exec);
06475    res |= ast_register_application_xml(app3, admin_exec);
06476    res |= ast_register_application_xml(app2, count_exec);
06477    res |= ast_register_application_xml(app, conf_exec);
06478    res |= ast_register_application_xml(slastation_app, sla_station_exec);
06479    res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
06480 
06481    res |= ast_devstate_prov_add("Meetme", meetmestate);
06482    res |= ast_devstate_prov_add("SLA", sla_state);
06483 
06484    res |= ast_custom_function_register(&meetme_info_acf);
06485    ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
06486 
06487    return res;
06488 }

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

Definition at line 1363 of file app_meetme.c.

References admin_exec(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_debug, ast_free, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd(), ast_cli_args::fd, ast_cli_args::line, MAX_CONFNUM, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

01364 {
01365    /* Process the command */
01366    struct ast_str *cmdline = NULL;
01367    int i = 0;
01368 
01369    switch (cmd) {
01370    case CLI_INIT:
01371       e->command = "meetme {lock|unlock|mute|unmute|kick}";
01372       e->usage =
01373          "Usage: meetme (un)lock|(un)mute|kick <confno> <usernumber>\n"
01374          "       Executes a command for the conference or on a conferee\n";
01375       return NULL;
01376    case CLI_GENERATE:
01377       return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01378    }
01379 
01380    if (a->argc > 8)
01381       ast_cli(a->fd, "Invalid Arguments.\n");
01382    /* Check for length so no buffer will overflow... */
01383    for (i = 0; i < a->argc; i++) {
01384       if (strlen(a->argv[i]) > 100)
01385          ast_cli(a->fd, "Invalid Arguments.\n");
01386    }
01387 
01388    /* Max confno length */
01389    if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01390       return CLI_FAILURE;
01391    }
01392 
01393    if (a->argc < 1) {
01394       ast_free(cmdline);
01395       return CLI_SHOWUSAGE;
01396    }
01397 
01398    ast_str_set(&cmdline, 0, "%s", a->argv[2]);  /* Argv 2: conference number */
01399    if (strstr(a->argv[1], "lock")) {
01400       if (strcmp(a->argv[1], "lock") == 0) {
01401          /* Lock */
01402          ast_str_append(&cmdline, 0, ",L");
01403       } else {
01404          /* Unlock */
01405          ast_str_append(&cmdline, 0, ",l");
01406       }
01407    } else if (strstr(a->argv[1], "mute")) { 
01408       if (a->argc < 4) {
01409          ast_free(cmdline);
01410          return CLI_SHOWUSAGE;
01411       }
01412       if (strcmp(a->argv[1], "mute") == 0) {
01413          /* Mute */
01414          if (strcmp(a->argv[3], "all") == 0) {
01415             ast_str_append(&cmdline, 0, ",N");
01416          } else {
01417             ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);  
01418          }
01419       } else {
01420          /* Unmute */
01421          if (strcmp(a->argv[3], "all") == 0) {
01422             ast_str_append(&cmdline, 0, ",n");
01423          } else {
01424             ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
01425          }
01426       }
01427    } else if (strcmp(a->argv[1], "kick") == 0) {
01428       if (a->argc < 4) {
01429          ast_free(cmdline);
01430          return CLI_SHOWUSAGE;
01431       }
01432       if (strcmp(a->argv[3], "all") == 0) {
01433          /* Kick all */
01434          ast_str_append(&cmdline, 0, ",K");
01435       } else {
01436          /* Kick a single user */
01437          ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
01438       }
01439    } else {
01440       ast_free(cmdline);
01441       return CLI_SHOWUSAGE;
01442    }
01443 
01444    ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
01445 
01446    admin_exec(NULL, ast_str_buffer(cmdline));
01447    ast_free(cmdline);
01448 
01449    return CLI_SUCCESS;
01450 }

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

Definition at line 1209 of file app_meetme.c.

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

01210 {
01211    /* Process the command */
01212    struct ast_conf_user *user;
01213    struct ast_conference *cnf;
01214    int hr, min, sec;
01215    int i = 0, total = 0;
01216    time_t now;
01217    struct ast_str *cmdline = NULL;
01218 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s  %-8s  %-6s\n"
01219 #define MC_DATA_FORMAT "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s  %-6s\n"
01220 
01221    switch (cmd) {
01222    case CLI_INIT:
01223       e->command = "meetme list [concise]";
01224       e->usage =
01225          "Usage: meetme list [concise] <confno> \n"
01226          "       List all or a specific conference.\n";
01227       return NULL;
01228    case CLI_GENERATE:
01229       return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01230    }
01231 
01232    /* Check for length so no buffer will overflow... */
01233    for (i = 0; i < a->argc; i++) {
01234       if (strlen(a->argv[i]) > 100)
01235          ast_cli(a->fd, "Invalid Arguments.\n");
01236    }
01237 
01238    /* Max confno length */
01239    if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01240       return CLI_FAILURE;
01241    }
01242 
01243    if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], "concise"))) {
01244       /* List all the conferences */   
01245       int concise = (a->argc == 3 && !strcasecmp(a->argv[2], "concise"));
01246       now = time(NULL);
01247       AST_LIST_LOCK(&confs);
01248       if (AST_LIST_EMPTY(&confs)) {
01249          if (!concise) {
01250             ast_cli(a->fd, "No active MeetMe conferences.\n");
01251          }
01252          AST_LIST_UNLOCK(&confs);
01253          ast_free(cmdline);
01254          return CLI_SUCCESS;
01255       }
01256       if (!concise) {
01257          ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
01258       }
01259       AST_LIST_TRAVERSE(&confs, cnf, list) {
01260          if (cnf->markedusers == 0) {
01261             ast_str_set(&cmdline, 0, "N/A ");
01262          } else {
01263             ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
01264          }
01265          hr = (now - cnf->start) / 3600;
01266          min = ((now - cnf->start) % 3600) / 60;
01267          sec = (now - cnf->start) % 60;
01268          if (!concise) {
01269             ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, ast_str_buffer(cmdline), hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
01270          } else {
01271             ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
01272                cnf->confno,
01273                cnf->users,
01274                cnf->markedusers,
01275                hr, min, sec,
01276                cnf->isdynamic,
01277                cnf->locked);
01278          }
01279 
01280          total += cnf->users;
01281       }
01282       AST_LIST_UNLOCK(&confs);
01283       if (!concise) {
01284          ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
01285       }
01286       ast_free(cmdline);
01287       return CLI_SUCCESS;
01288    } else if (strcmp(a->argv[1], "list") == 0) {
01289       int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
01290       /* List all the users in a conference */
01291       if (AST_LIST_EMPTY(&confs)) {
01292          if (!concise) {
01293             ast_cli(a->fd, "No active MeetMe conferences.\n");
01294          }
01295          ast_free(cmdline);
01296          return CLI_SUCCESS;  
01297       }
01298       /* Find the right conference */
01299       AST_LIST_LOCK(&confs);
01300       AST_LIST_TRAVERSE(&confs, cnf, list) {
01301          if (strcmp(cnf->confno, a->argv[2]) == 0) {
01302             break;
01303          }
01304       }
01305       if (!cnf) {
01306          if (!concise)
01307             ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
01308          AST_LIST_UNLOCK(&confs);
01309          ast_free(cmdline);
01310          return CLI_SUCCESS;
01311       }
01312       /* Show all the users */
01313       time(&now);
01314       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
01315          hr = (now - user->jointime) / 3600;
01316          min = ((now - user->jointime) % 3600) / 60;
01317          sec = (now - user->jointime) % 60;
01318          if (!concise) {
01319             ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
01320                user->user_no,
01321                S_OR(user->chan->cid.cid_num, "<unknown>"),
01322                S_OR(user->chan->cid.cid_name, "<no name>"),
01323                user->chan->name,
01324                user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
01325                user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
01326                user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
01327                user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
01328                istalking(user->talking), hr, min, sec); 
01329          } else {
01330             ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
01331                user->user_no,
01332                S_OR(user->chan->cid.cid_num, ""),
01333                S_OR(user->chan->cid.cid_name, ""),
01334                user->chan->name,
01335                user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
01336                user->userflags  & CONFFLAG_MONITOR ? "1" : "",
01337                user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
01338                user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
01339                user->talking, hr, min, sec);
01340          }
01341       }
01342       if (!concise) {
01343          ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
01344       }
01345       AST_LIST_UNLOCK(&confs);
01346       ast_free(cmdline);
01347       return CLI_SUCCESS;
01348    }
01349    if (a->argc < 2) {
01350       ast_free(cmdline);
01351       return CLI_SHOWUSAGE;
01352    }
01353 
01354    ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
01355 
01356    admin_exec(NULL, ast_str_buffer(cmdline));
01357    ast_free(cmdline);
01358 
01359    return CLI_SUCCESS;
01360 }

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

Definition at line 4213 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), ast_conf_user::chan, ast_conference::confno, ast_conf_user::list, LOG_NOTICE, ast_channel::name, ast_channel::uniqueid, ast_conf_user::user_no, and ast_conference::userlist.

Referenced by action_meetmemute(), and action_meetmeunmute().

04214 {
04215    struct ast_conference *conf;
04216    struct ast_conf_user *user;
04217    const char *confid = astman_get_header(m, "Meetme");
04218    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
04219    int userno;
04220 
04221    if (ast_strlen_zero(confid)) {
04222       astman_send_error(s, m, "Meetme conference not specified");
04223       return 0;
04224    }
04225 
04226    if (ast_strlen_zero(userid)) {
04227       astman_send_error(s, m, "Meetme user number not specified");
04228       return 0;
04229    }
04230 
04231    userno = strtoul(userid, &userid, 10);
04232 
04233    if (*userid) {
04234       astman_send_error(s, m, "Invalid user number");
04235       return 0;
04236    }
04237 
04238    /* Look in the conference list */
04239    AST_LIST_LOCK(&confs);
04240    AST_LIST_TRAVERSE(&confs, conf, list) {
04241       if (!strcmp(confid, conf->confno))
04242          break;
04243    }
04244 
04245    if (!conf) {
04246       AST_LIST_UNLOCK(&confs);
04247       astman_send_error(s, m, "Meetme conference does not exist");
04248       return 0;
04249    }
04250 
04251    AST_LIST_TRAVERSE(&conf->userlist, user, list)
04252       if (user->user_no == userno)
04253          break;
04254 
04255    if (!user) {
04256       AST_LIST_UNLOCK(&confs);
04257       astman_send_error(s, m, "User number not found");
04258       return 0;
04259    }
04260 
04261    if (mute)
04262       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
04263    else
04264       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
04265 
04266    AST_LIST_UNLOCK(&confs);
04267 
04268    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);
04269 
04270    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
04271    return 0;
04272 }

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

Callback for devicestate providers.

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

04425 {
04426    struct ast_conference *conf;
04427 
04428    /* Find conference */
04429    AST_LIST_LOCK(&confs);
04430    AST_LIST_TRAVERSE(&confs, conf, list) {
04431       if (!strcmp(data, conf->confno))
04432          break;
04433    }
04434    AST_LIST_UNLOCK(&confs);
04435    if (!conf)
04436       return AST_DEVICE_INVALID;
04437 
04438 
04439    /* SKREP to fill */
04440    if (!conf->users)
04441       return AST_DEVICE_NOT_INUSE;
04442 
04443    return AST_DEVICE_INUSE;
04444 }

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

Definition at line 5774 of file app_meetme.c.

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

Referenced by sla_trunk_exec().

05775 {
05776    struct sla_ringing_trunk *ringing_trunk;
05777 
05778    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
05779       return NULL;
05780    
05781    ringing_trunk->trunk = trunk;
05782    ringing_trunk->ring_begin = ast_tvnow();
05783 
05784    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
05785 
05786    ast_mutex_lock(&sla.lock);
05787    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
05788    ast_mutex_unlock(&sla.lock);
05789 
05790    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05791 
05792    return ringing_trunk;
05793 }

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

Definition at line 4359 of file app_meetme.c.

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

04360 {
04361    struct ast_conference *cnf = args;
04362    struct ast_frame *f = NULL;
04363    int flags;
04364    struct ast_filestream *s = NULL;
04365    int res = 0;
04366    int x;
04367    const char *oldrecordingfilename = NULL;
04368 
04369    if (!cnf || !cnf->lchan) {
04370       pthread_exit(0);
04371    }
04372 
04373    ast_stopstream(cnf->lchan);
04374    flags = O_CREAT | O_TRUNC | O_WRONLY;
04375 
04376 
04377    cnf->recording = MEETME_RECORD_ACTIVE;
04378    while (ast_waitfor(cnf->lchan, -1) > -1) {
04379       if (cnf->recording == MEETME_RECORD_TERMINATE) {
04380          AST_LIST_LOCK(&confs);
04381          AST_LIST_UNLOCK(&confs);
04382          break;
04383       }
04384       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
04385          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
04386          oldrecordingfilename = cnf->recordingfilename;
04387       }
04388       
04389       f = ast_read(cnf->lchan);
04390       if (!f) {
04391          res = -1;
04392          break;
04393       }
04394       if (f->frametype == AST_FRAME_VOICE) {
04395          ast_mutex_lock(&cnf->listenlock);
04396          for (x = 0; x < AST_FRAME_BITS; x++) {
04397             /* Free any translations that have occured */
04398             if (cnf->transframe[x]) {
04399                ast_frfree(cnf->transframe[x]);
04400                cnf->transframe[x] = NULL;
04401             }
04402          }
04403          if (cnf->origframe)
04404             ast_frfree(cnf->origframe);
04405          cnf->origframe = ast_frdup(f);
04406          ast_mutex_unlock(&cnf->listenlock);
04407          if (s)
04408             res = ast_writestream(s, f);
04409          if (res) {
04410             ast_frfree(f);
04411             break;
04412          }
04413       }
04414       ast_frfree(f);
04415    }
04416    cnf->recording = MEETME_RECORD_OFF;
04417    if (s)
04418       ast_closestream(s);
04419    
04420    pthread_exit(0);
04421 }

static int reload ( void   )  [static]

Definition at line 6490 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

06491 {
06492    ast_unload_realtime("meetme");
06493    return load_config(1);
06494 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 1005 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

01006 {
01007    signed char zero_volume = 0;
01008 
01009    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
01010    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
01011 }

static int rt_extend_conf ( char *  confno  )  [static]

Definition at line 1815 of file app_meetme.c.

References ast_copy_string(), ast_debug, ast_load_realtime(), ast_localtime(), ast_mktime(), ast_strftime(), ast_strptime(), ast_tvnow(), ast_update_realtime(), ast_variables_destroy(), DATE_FORMAT, ast_variable::name, ast_variable::next, ast_variable::value, and var.

Referenced by admin_exec(), and conf_run().

01816 {
01817    char currenttime[32];
01818    char endtime[32];
01819    struct timeval now;
01820    struct ast_tm tm;
01821    struct ast_variable *var, *orig_var;
01822    char bookid[51];
01823 
01824    if (!extendby) {
01825       return 0;
01826    }
01827 
01828    now = ast_tvnow();
01829 
01830    ast_localtime(&now, &tm, NULL);
01831    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
01832 
01833    var = ast_load_realtime("meetme", "confno",
01834       confno, "startTime<= ", currenttime,
01835       "endtime>= ", currenttime, NULL);
01836 
01837    orig_var = var;
01838 
01839    /* Identify the specific RealTime conference */
01840    while (var) {
01841       if (!strcasecmp(var->name, "bookid")) {
01842          ast_copy_string(bookid, var->value, sizeof(bookid));
01843       }
01844       if (!strcasecmp(var->name, "endtime")) {
01845          ast_copy_string(endtime, var->value, sizeof(endtime));
01846       }
01847 
01848       var = var->next;
01849    }
01850    ast_variables_destroy(orig_var);
01851 
01852    ast_strptime(endtime, DATE_FORMAT, &tm);
01853    now = ast_mktime(&tm, NULL);
01854 
01855    now.tv_sec += extendby;
01856 
01857    ast_localtime(&now, &tm, NULL);
01858    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
01859    strcat(currenttime, "0"); /* Seconds needs to be 00 */
01860 
01861    var = ast_load_realtime("meetme", "confno",
01862       confno, "startTime<= ", currenttime,
01863       "endtime>= ", currenttime, NULL);
01864 
01865    /* If there is no conflict with extending the conference, update the DB */
01866    if (!var) {
01867       ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
01868       ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
01869       return 0;
01870 
01871    }
01872 
01873    ast_variables_destroy(var);
01874    return -1;
01875 }

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

Definition at line 4673 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_buffer(), 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, sla_trunk_ref::trunk, and run_station_args::trunk_ref.

Referenced by sla_handle_dial_state_event().

04674 {
04675    struct sla_station *station;
04676    struct sla_trunk_ref *trunk_ref;
04677    struct ast_str *conf_name = ast_str_create(16);
04678    struct ast_flags conf_flags = { 0 };
04679    struct ast_conference *conf;
04680 
04681    {
04682       struct run_station_args *args = data;
04683       station = args->station;
04684       trunk_ref = args->trunk_ref;
04685       ast_mutex_lock(args->cond_lock);
04686       ast_cond_signal(args->cond);
04687       ast_mutex_unlock(args->cond_lock);
04688       /* args is no longer valid here. */
04689    }
04690 
04691    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
04692    ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
04693    ast_set_flag(&conf_flags, 
04694       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04695    answer_trunk_chan(trunk_ref->chan);
04696    conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan);
04697    if (conf) {
04698       conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
04699       dispose_conf(conf);
04700       conf = NULL;
04701    }
04702    trunk_ref->chan = NULL;
04703    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04704       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04705       ast_str_append(&conf_name, 0, ",K");
04706       admin_exec(NULL, ast_str_buffer(conf_name));
04707       trunk_ref->trunk->hold_stations = 0;
04708       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04709    }
04710 
04711    ast_dial_join(station->dial);
04712    ast_dial_destroy(station->dial);
04713    station->dial = NULL;
04714    ast_free(conf_name);
04715 
04716    return NULL;
04717 }

static void send_talking_event ( struct ast_channel chan,
struct ast_conference conf,
struct ast_conf_user user,
int  talking 
) [static]

Definition at line 1969 of file app_meetme.c.

References ast_conference::confno, EVENT_FLAG_CALL, manager_event, ast_channel::name, ast_channel::uniqueid, and ast_conf_user::user_no.

Referenced by set_user_talking().

01970 {
01971    manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
01972          "Channel: %s\r\n"
01973          "Uniqueid: %s\r\n"
01974          "Meetme: %s\r\n"
01975          "Usernum: %d\r\n"
01976          "Status: %s\r\n",
01977          chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
01978 }

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

Definition at line 934 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

00935 {
00936    char gain_adjust;
00937 
00938    /* attempt to make the adjustment in the channel driver;
00939       if successful, don't adjust in the frame reading routine
00940    */
00941    gain_adjust = gain_map[volume + 5];
00942 
00943    return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00944 }

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

Definition at line 922 of file app_meetme.c.

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

Referenced by conf_run(), and tweak_talk_volume().

00923 {
00924    char gain_adjust;
00925 
00926    /* attempt to make the adjustment in the channel driver;
00927       if successful, don't adjust in the frame reading routine
00928    */
00929    gain_adjust = gain_map[volume + 5];
00930 
00931    return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00932 }

static void set_user_talking ( struct ast_channel chan,
struct ast_conference conf,
struct ast_conf_user user,
int  talking,
int  monitor 
) [static]

Definition at line 1980 of file app_meetme.c.

References send_talking_event(), and ast_conf_user::talking.

Referenced by conf_run().

01981 {
01982    int last_talking = user->talking;
01983    if (last_talking == talking)
01984       return;
01985 
01986    user->talking = talking;
01987 
01988    if (monitor) {
01989       /* Check if talking state changed. Take care of -1 which means unmonitored */
01990       int was_talking = (last_talking > 0);
01991       int now_talking = (talking > 0);
01992       if (was_talking != now_talking) {
01993          send_talking_event(chan, conf, user, now_talking);
01994       }
01995    }
01996 }

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

Definition at line 6120 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, create_trunk_ref(), LOG_ERROR, LOG_WARNING, sla_station::name, sla_trunk::name, sla_trunk::num_stations, sla_trunk_ref::ring_delay, sla_trunk_ref::ring_timeout, sla_create_station_ref(), SLA_TRUNK_STATE_IDLE, sla_trunk_ref::state, sla_trunk::stations, sla_station::trunks, and ast_variable::value.

Referenced by sla_build_station().

06121 {
06122    struct sla_trunk *trunk;
06123    struct sla_trunk_ref *trunk_ref;
06124    struct sla_station_ref *station_ref;
06125    char *trunk_name, *options, *cur;
06126 
06127    options = ast_strdupa(var->value);
06128    trunk_name = strsep(&options, ",");
06129    
06130    AST_RWLIST_RDLOCK(&sla_trunks);
06131    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
06132       if (!strcasecmp(trunk->name, trunk_name))
06133          break;
06134    }
06135 
06136    AST_RWLIST_UNLOCK(&sla_trunks);
06137    if (!trunk) {
06138       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
06139       return;
06140    }
06141    if (!(trunk_ref = create_trunk_ref(trunk)))
06142       return;
06143    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
06144 
06145    while ((cur = strsep(&options, ","))) {
06146       char *name, *value = cur;
06147       name = strsep(&value, "=");
06148       if (!strcasecmp(name, "ringtimeout")) {
06149          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
06150             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
06151                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06152             trunk_ref->ring_timeout = 0;
06153          }
06154       } else if (!strcasecmp(name, "ringdelay")) {
06155          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
06156             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
06157                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06158             trunk_ref->ring_delay = 0;
06159          }
06160       } else {
06161          ast_log(LOG_WARNING, "Invalid option '%s' for "
06162             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
06163       }
06164    }
06165 
06166    if (!(station_ref = sla_create_station_ref(station))) {
06167       ast_free(trunk_ref);
06168       return;
06169    }
06170    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
06171    AST_RWLIST_WRLOCK(&sla_trunks);
06172    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
06173    AST_RWLIST_UNLOCK(&sla_trunks);
06174    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
06175 }

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

Definition at line 6177 of file app_meetme.c.

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

Referenced by sla_load_config().

06178 {
06179    struct sla_station *station;
06180    struct ast_variable *var;
06181    const char *dev;
06182 
06183    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06184       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
06185       return -1;
06186    }
06187 
06188    if (!(station = ast_calloc(1, sizeof(*station))))
06189       return -1;
06190    if (ast_string_field_init(station, 32)) {
06191       ast_free(station);
06192       return -1;
06193    }
06194 
06195    ast_string_field_set(station, name, cat);
06196    ast_string_field_set(station, device, dev);
06197 
06198    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06199       if (!strcasecmp(var->name, "trunk"))
06200          sla_add_trunk_to_station(station, var);
06201       else if (!strcasecmp(var->name, "autocontext"))
06202          ast_string_field_set(station, autocontext, var->value);
06203       else if (!strcasecmp(var->name, "ringtimeout")) {
06204          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
06205             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
06206                var->value, station->name);
06207             station->ring_timeout = 0;
06208          }
06209       } else if (!strcasecmp(var->name, "ringdelay")) {
06210          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
06211             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
06212                var->value, station->name);
06213             station->ring_delay = 0;
06214          }
06215       } else if (!strcasecmp(var->name, "hold")) {
06216          if (!strcasecmp(var->value, "private"))
06217             station->hold_access = SLA_HOLD_PRIVATE;
06218          else if (!strcasecmp(var->value, "open"))
06219             station->hold_access = SLA_HOLD_OPEN;
06220          else {
06221             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
06222                var->value, station->name);
06223          }
06224 
06225       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06226          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06227             var->name, var->lineno, SLA_CONFIG_FILE);
06228       }
06229    }
06230 
06231    if (!ast_strlen_zero(station->autocontext)) {
06232       struct ast_context *context;
06233       struct sla_trunk_ref *trunk_ref;
06234       context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
06235       if (!context) {
06236          ast_log(LOG_ERROR, "Failed to automatically find or create "
06237             "context '%s' for SLA!\n", station->autocontext);
06238          destroy_station(station);
06239          return -1;
06240       }
06241       /* The extension for when the handset goes off-hook.
06242        * exten => station1,1,SLAStation(station1) */
06243       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
06244          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
06245          ast_log(LOG_ERROR, "Failed to automatically create extension "
06246             "for trunk '%s'!\n", station->name);
06247          destroy_station(station);
06248          return -1;
06249       }
06250       AST_RWLIST_RDLOCK(&sla_trunks);
06251       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06252          char exten[AST_MAX_EXTENSION];
06253          char hint[AST_MAX_APP];
06254          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06255          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06256          /* Extension for this line button 
06257           * exten => station1_line1,1,SLAStation(station1_line1) */
06258          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
06259             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
06260             ast_log(LOG_ERROR, "Failed to automatically create extension "
06261                "for trunk '%s'!\n", station->name);
06262             destroy_station(station);
06263             return -1;
06264          }
06265          /* Hint for this line button 
06266           * exten => station1_line1,hint,SLA:station1_line1 */
06267          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
06268             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
06269             ast_log(LOG_ERROR, "Failed to automatically create hint "
06270                "for trunk '%s'!\n", station->name);
06271             destroy_station(station);
06272             return -1;
06273          }
06274       }
06275       AST_RWLIST_UNLOCK(&sla_trunks);
06276    }
06277 
06278    AST_RWLIST_WRLOCK(&sla_stations);
06279    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
06280    AST_RWLIST_UNLOCK(&sla_stations);
06281 
06282    return 0;
06283 }

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

Definition at line 6042 of file app_meetme.c.

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

Referenced by sla_load_config().

06043 {
06044    struct sla_trunk *trunk;
06045    struct ast_variable *var;
06046    const char *dev;
06047 
06048    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06049       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
06050       return -1;
06051    }
06052 
06053    if (sla_check_device(dev)) {
06054       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
06055          cat, dev);
06056       return -1;
06057    }
06058 
06059    if (!(trunk = ast_calloc(1, sizeof(*trunk))))
06060       return -1;
06061    if (ast_string_field_init(trunk, 32)) {
06062       ast_free(trunk);
06063       return -1;
06064    }
06065 
06066    ast_string_field_set(trunk, name, cat);
06067    ast_string_field_set(trunk, device, dev);
06068 
06069    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06070       if (!strcasecmp(var->name, "autocontext"))
06071          ast_string_field_set(trunk, autocontext, var->value);
06072       else if (!strcasecmp(var->name, "ringtimeout")) {
06073          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
06074             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
06075                var->value, trunk->name);
06076             trunk->ring_timeout = 0;
06077          }
06078       } else if (!strcasecmp(var->name, "barge"))
06079          trunk->barge_disabled = ast_false(var->value);
06080       else if (!strcasecmp(var->name, "hold")) {
06081          if (!strcasecmp(var->value, "private"))
06082             trunk->hold_access = SLA_HOLD_PRIVATE;
06083          else if (!strcasecmp(var->value, "open"))
06084             trunk->hold_access = SLA_HOLD_OPEN;
06085          else {
06086             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
06087                var->value, trunk->name);
06088          }
06089       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06090          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06091             var->name, var->lineno, SLA_CONFIG_FILE);
06092       }
06093    }
06094 
06095    if (!ast_strlen_zero(trunk->autocontext)) {
06096       struct ast_context *context;
06097       context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
06098       if (!context) {
06099          ast_log(LOG_ERROR, "Failed to automatically find or create "
06100             "context '%s' for SLA!\n", trunk->autocontext);
06101          destroy_trunk(trunk);
06102          return -1;
06103       }
06104       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
06105          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
06106          ast_log(LOG_ERROR, "Failed to automatically create extension "
06107             "for trunk '%s'!\n", trunk->name);
06108          destroy_trunk(trunk);
06109          return -1;
06110       }
06111    }
06112 
06113    AST_RWLIST_WRLOCK(&sla_trunks);
06114    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
06115    AST_RWLIST_UNLOCK(&sla_trunks);
06116 
06117    return 0;
06118 }

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

References AST_LIST_TRAVERSE, sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), and sla_choose_ringing_trunk().

Referenced by sla_process_timers().

05287 {
05288    struct sla_station *station;
05289    int res = 0;
05290 
05291    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05292       struct sla_ringing_trunk *ringing_trunk;
05293       int time_left;
05294 
05295       /* Ignore stations already ringing */
05296       if (sla_check_ringing_station(station))
05297          continue;
05298 
05299       /* Ignore stations already on a call */
05300       if (sla_check_inuse_station(station))
05301          continue;
05302 
05303       /* Ignore stations that don't have one of their trunks ringing */
05304       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
05305          continue;
05306 
05307       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
05308          continue;
05309 
05310       /* If there is no time left, then the station needs to start ringing.
05311        * Return non-zero so that an event will be queued up an event to 
05312        * make that happen. */
05313       if (time_left <= 0) {
05314          res = 1;
05315          continue;
05316       }
05317 
05318       if (time_left < *timeout)
05319          *timeout = time_left;
05320    }
05321 
05322    return res;
05323 }

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

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

Referenced by sla_process_timers().

05204 {
05205    struct sla_ringing_trunk *ringing_trunk;
05206    struct sla_ringing_station *ringing_station;
05207    int res = 0;
05208 
05209    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05210       unsigned int ring_timeout = 0;
05211       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
05212       struct sla_trunk_ref *trunk_ref;
05213 
05214       /* If there are any ring timeouts specified for a specific trunk
05215        * on the station, then use the highest per-trunk ring timeout.
05216        * Otherwise, use the ring timeout set for the entire station. */
05217       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05218          struct sla_station_ref *station_ref;
05219          int trunk_time_elapsed, trunk_time_left;
05220 
05221          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05222             if (ringing_trunk->trunk == trunk_ref->trunk)
05223                break;
05224          }
05225          if (!ringing_trunk)
05226             continue;
05227 
05228          /* If there is a trunk that is ringing without a timeout, then the
05229           * only timeout that could matter is a global station ring timeout. */
05230          if (!trunk_ref->ring_timeout)
05231             break;
05232 
05233          /* This trunk on this station is ringing and has a timeout.
05234           * However, make sure this trunk isn't still ringing from a
05235           * previous timeout.  If so, don't consider it. */
05236          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
05237             if (station_ref->station == ringing_station->station)
05238                break;
05239          }
05240          if (station_ref)
05241             continue;
05242 
05243          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05244          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
05245          if (trunk_time_left > final_trunk_time_left)
05246             final_trunk_time_left = trunk_time_left;
05247       }
05248 
05249       /* No timeout was found for ringing trunks, and no timeout for the entire station */
05250       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
05251          continue;
05252 
05253       /* Compute how much time is left for a global station timeout */
05254       if (ringing_station->station->ring_timeout) {
05255          ring_timeout = ringing_station->station->ring_timeout;
05256          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
05257          time_left = (ring_timeout * 1000) - time_elapsed;
05258       }
05259 
05260       /* If the time left based on the per-trunk timeouts is smaller than the
05261        * global station ring timeout, use that. */
05262       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
05263          time_left = final_trunk_time_left;
05264 
05265       /* If there is no time left, the station needs to stop ringing */
05266       if (time_left <= 0) {
05267          AST_LIST_REMOVE_CURRENT(entry);
05268          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
05269          res = 1;
05270          continue;
05271       }
05272 
05273       /* There is still some time left for this station to ring, so save that
05274        * timeout if it is the first event scheduled to occur */
05275       if (time_left < *timeout)
05276          *timeout = time_left;
05277    }
05278    AST_LIST_TRAVERSE_SAFE_END;
05279 
05280    return res;
05281 }

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

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

Referenced by sla_process_timers().

05174 {
05175    struct sla_ringing_trunk *ringing_trunk;
05176    int res = 0;
05177 
05178    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05179       int time_left, time_elapsed;
05180       if (!ringing_trunk->trunk->ring_timeout)
05181          continue;
05182       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05183       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
05184       if (time_left <= 0) {
05185          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
05186          AST_LIST_REMOVE_CURRENT(entry);
05187          sla_stop_ringing_trunk(ringing_trunk);
05188          res = 1;
05189          continue;
05190       }
05191       if (time_left < *timeout)
05192          *timeout = time_left;
05193    }
05194    AST_LIST_TRAVERSE_SAFE_END;
05195 
05196    return res;
05197 }

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

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

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

04643 {
04644    struct sla_station *station;
04645    struct sla_trunk_ref *trunk_ref;
04646 
04647    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04648       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04649          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
04650             || trunk_ref == exclude)
04651             continue;
04652          trunk_ref->state = state;
04653          ast_devstate_changed(sla_state_to_devstate(state), 
04654             "SLA:%s_%s", station->name, trunk->name);
04655          break;
04656       }
04657    }
04658 }

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

Definition at line 6029 of file app_meetme.c.

References ast_strlen_zero().

Referenced by sla_build_trunk().

06030 {
06031    char *tech, *tech_data;
06032 
06033    tech_data = ast_strdupa(device);
06034    tech = strsep(&tech_data, "/");
06035 
06036    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
06037       return -1;
06038 
06039    return 0;
06040 }

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

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

Referenced by sla_ring_stations().

04922 {
04923    struct sla_failed_station *failed_station;
04924    int res = 0;
04925 
04926    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
04927       if (station != failed_station->station)
04928          continue;
04929       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
04930          AST_LIST_REMOVE_CURRENT(entry);
04931          ast_free(failed_station);
04932          break;
04933       }
04934       res = 1;
04935    }
04936    AST_LIST_TRAVERSE_SAFE_END
04937 
04938    return res;
04939 }

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

Check to see if a station is in use.

Definition at line 5007 of file app_meetme.c.

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

Referenced by sla_calc_station_delays(), and sla_ring_stations().

05008 {
05009    struct sla_trunk_ref *trunk_ref;
05010 
05011    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05012       if (trunk_ref->chan)
05013          return 1;
05014    }
05015 
05016    return 0;
05017 }

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

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

Referenced by sla_thread().

05366 {
05367    struct sla_station *station;
05368    struct sla_trunk *trunk;
05369 
05370    ast_mutex_lock(&sla.lock);
05371 
05372    if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
05373       || !AST_LIST_EMPTY(&sla.ringing_stations)) {
05374       ast_mutex_unlock(&sla.lock);
05375       return;
05376    }
05377 
05378    AST_RWLIST_RDLOCK(&sla_stations);
05379    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
05380       if (station->ref_count)
05381          break;
05382    }
05383    AST_RWLIST_UNLOCK(&sla_stations);
05384    if (station) {
05385       ast_mutex_unlock(&sla.lock);
05386       return;
05387    }
05388 
05389    AST_RWLIST_RDLOCK(&sla_trunks);
05390    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05391       if (trunk->ref_count)
05392          break;
05393    }
05394    AST_RWLIST_UNLOCK(&sla_trunks);
05395    if (trunk) {
05396       ast_mutex_unlock(&sla.lock);
05397       return;
05398    }
05399 
05400    /* yay */
05401    sla_load_config(1);
05402    sla.reload = 0;
05403 
05404    ast_mutex_unlock(&sla.lock);
05405 }

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

References AST_LIST_TRAVERSE, sla, and sla_ringing_station::station.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

04907 {
04908    struct sla_ringing_station *ringing_station;
04909 
04910    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
04911       if (station == ringing_station->station)
04912          return 1;
04913    }
04914 
04915    return 0;
04916 }

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

05039 {
05040    struct sla_trunk_ref *trunk_ref;
05041    unsigned int delay = UINT_MAX;
05042    int time_left, time_elapsed;
05043 
05044    if (!ringing_trunk)
05045       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
05046    else
05047       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
05048 
05049    if (!ringing_trunk || !trunk_ref)
05050       return delay;
05051 
05052    /* If this station has a ring delay specific to the highest priority
05053     * ringing trunk, use that.  Otherwise, use the ring delay specified
05054     * globally for the station. */
05055    delay = trunk_ref->ring_delay;
05056    if (!delay)
05057       delay = station->ring_delay;
05058    if (!delay)
05059       return INT_MAX;
05060 
05061    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05062    time_left = (delay * 1000) - time_elapsed;
05063 
05064    return time_left;
05065 }

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

Definition at line 4546 of file app_meetme.c.

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

Referenced by sla_find_trunk_ref_byname().

04548 {
04549    struct sla_station_ref *station_ref;
04550    struct sla_trunk_ref *trunk_ref;
04551 
04552    /* For each station that has this call on hold, check for private hold. */
04553    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
04554       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
04555          if (trunk_ref->trunk != trunk || station_ref->station == station)
04556             continue;
04557          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
04558             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
04559             return 1;
04560          return 0;
04561       }
04562    }
04563 
04564    return 0;
04565 }

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

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

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

04779 {
04780    struct sla_station_ref *timed_out_station;
04781 
04782    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
04783       if (station == timed_out_station->station)
04784          return 1;
04785    }
04786 
04787    return 0;
04788 }

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

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

Definition at line 5589 of file app_meetme.c.

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

Referenced by sla_station_exec().

05590 {
05591    struct sla_trunk_ref *trunk_ref = NULL;
05592 
05593    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05594       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
05595          break;
05596    }
05597 
05598    return trunk_ref;
05599 }

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

Choose the highest priority ringing trunk for a station.

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

Definition at line 4798 of file app_meetme.c.

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, sla, sla_check_timed_out_station(), sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and sla_station::trunks.

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

04800 {
04801    struct sla_trunk_ref *s_trunk_ref;
04802    struct sla_ringing_trunk *ringing_trunk = NULL;
04803 
04804    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
04805       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04806          /* Make sure this is the trunk we're looking for */
04807          if (s_trunk_ref->trunk != ringing_trunk->trunk)
04808             continue;
04809 
04810          /* This trunk on the station is ringing.  But, make sure this station
04811           * didn't already time out while this trunk was ringing. */
04812          if (sla_check_timed_out_station(ringing_trunk, station))
04813             continue;
04814 
04815          if (rm)
04816             AST_LIST_REMOVE_CURRENT(entry);
04817 
04818          if (trunk_ref)
04819             *trunk_ref = s_trunk_ref;
04820 
04821          break;
04822       }
04823       AST_LIST_TRAVERSE_SAFE_END;
04824    
04825       if (ringing_trunk)
04826          break;
04827    }
04828 
04829    return ringing_trunk;
04830 }

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

Definition at line 4611 of file app_meetme.c.

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

Referenced by sla_ring_station().

04612 {
04613    struct sla_ringing_station *ringing_station;
04614 
04615    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
04616       return NULL;
04617 
04618    ringing_station->station = station;
04619    ringing_station->ring_begin = ast_tvnow();
04620 
04621    return ringing_station;
04622 }

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

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

04600 {
04601    struct sla_station_ref *station_ref;
04602 
04603    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
04604       return NULL;
04605 
04606    station_ref->station = station;
04607 
04608    return station_ref;
04609 }

static void sla_destroy ( void   )  [static]

Definition at line 5999 of file app_meetme.c.

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

Referenced by unload_module().

06000 {
06001    struct sla_trunk *trunk;
06002    struct sla_station *station;
06003 
06004    AST_RWLIST_WRLOCK(&sla_trunks);
06005    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
06006       destroy_trunk(trunk);
06007    AST_RWLIST_UNLOCK(&sla_trunks);
06008 
06009    AST_RWLIST_WRLOCK(&sla_stations);
06010    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
06011       destroy_station(station);
06012    AST_RWLIST_UNLOCK(&sla_stations);
06013 
06014    if (sla.thread != AST_PTHREADT_NULL) {
06015       ast_mutex_lock(&sla.lock);
06016       sla.stop = 1;
06017       ast_cond_signal(&sla.cond);
06018       ast_mutex_unlock(&sla.lock);
06019       pthread_join(sla.thread, NULL);
06020    }
06021 
06022    /* Drop any created contexts from the dialplan */
06023    ast_context_destroy(NULL, sla_registrar);
06024 
06025    ast_mutex_destroy(&sla.lock);
06026    ast_cond_destroy(&sla.cond);
06027 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 4769 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

04770 {
04771    sla_queue_event(SLA_EVENT_DIAL_STATE);
04772 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 4534 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, and sla_station::name.

Referenced by sla_station_exec().

04535 {
04536    struct sla_station *station = NULL;
04537 
04538    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
04539       if (!strcasecmp(station->name, name))
04540          break;
04541    }
04542 
04543    return station;
04544 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 4519 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, and sla_trunk::name.

Referenced by sla_trunk_exec().

04520 {
04521    struct sla_trunk *trunk = NULL;
04522 
04523    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04524       if (!strcasecmp(trunk->name, name))
04525          break;
04526    }
04527 
04528    return trunk;
04529 }

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

Definition at line 5019 of file app_meetme.c.

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

Referenced by sla_check_station_delay().

05021 {
05022    struct sla_trunk_ref *trunk_ref = NULL;
05023 
05024    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05025       if (trunk_ref->trunk == trunk)
05026          break;
05027    }
05028 
05029    return trunk_ref;
05030 }

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

Find a trunk reference on a station by name.

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

Definition at line 4574 of file app_meetme.c.

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

Referenced by sla_station_exec().

04576 {
04577    struct sla_trunk_ref *trunk_ref = NULL;
04578 
04579    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04580       if (strcasecmp(trunk_ref->trunk->name, name))
04581          continue;
04582 
04583       if ( (trunk_ref->trunk->barge_disabled 
04584          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
04585          (trunk_ref->trunk->hold_stations 
04586          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
04587          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
04588          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
04589       {
04590          trunk_ref = NULL;
04591       }
04592 
04593       break;
04594    }
04595 
04596    return trunk_ref;
04597 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 4832 of file app_meetme.c.

References ALL_TRUNK_REFS, answer_trunk_chan(), ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), ast_debug, ast_dial_answered(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_state(), ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_detached_background, sla_trunk::chan, sla_trunk_ref::chan, run_station_args::cond, run_station_args::cond_lock, sla_station::dial, sla_station::name, run_station(), sla, sla_change_trunk_state(), sla_choose_ringing_trunk(), SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_queue_event(), SLA_STATION_HANGUP_NORMAL, sla_stop_ringing_station(), SLA_TRUNK_STATE_UP, run_station_args::station, sla_ringing_station::station, sla_ringing_trunk::trunk, and run_station_args::trunk_ref.

Referenced by sla_thread().

04833 {
04834    struct sla_ringing_station *ringing_station;
04835 
04836    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04837       struct sla_trunk_ref *s_trunk_ref = NULL;
04838       struct sla_ringing_trunk *ringing_trunk = NULL;
04839       struct run_station_args args;
04840       enum ast_dial_result dial_res;
04841       pthread_t dont_care;
04842       ast_mutex_t cond_lock;
04843       ast_cond_t cond;
04844 
04845       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
04846       case AST_DIAL_RESULT_HANGUP:
04847       case AST_DIAL_RESULT_INVALID:
04848       case AST_DIAL_RESULT_FAILED:
04849       case AST_DIAL_RESULT_TIMEOUT:
04850       case AST_DIAL_RESULT_UNANSWERED:
04851          AST_LIST_REMOVE_CURRENT(entry);
04852          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
04853          break;
04854       case AST_DIAL_RESULT_ANSWERED:
04855          AST_LIST_REMOVE_CURRENT(entry);
04856          /* Find the appropriate trunk to answer. */
04857          ast_mutex_lock(&sla.lock);
04858          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
04859          ast_mutex_unlock(&sla.lock);
04860          if (!ringing_trunk) {
04861             ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
04862             break;
04863          }
04864          /* Track the channel that answered this trunk */
04865          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
04866          /* Actually answer the trunk */
04867          answer_trunk_chan(ringing_trunk->trunk->chan);
04868          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04869          /* Now, start a thread that will connect this station to the trunk.  The rest of
04870           * the code here sets up the thread and ensures that it is able to save the arguments
04871           * before they are no longer valid since they are allocated on the stack. */
04872          args.trunk_ref = s_trunk_ref;
04873          args.station = ringing_station->station;
04874          args.cond = &cond;
04875          args.cond_lock = &cond_lock;
04876          ast_free(ringing_trunk);
04877          ast_free(ringing_station);
04878          ast_mutex_init(&cond_lock);
04879          ast_cond_init(&cond, NULL);
04880          ast_mutex_lock(&cond_lock);
04881          ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
04882          ast_cond_wait(&cond, &cond_lock);
04883          ast_mutex_unlock(&cond_lock);
04884          ast_mutex_destroy(&cond_lock);
04885          ast_cond_destroy(&cond);
04886          break;
04887       case AST_DIAL_RESULT_TRYING:
04888       case AST_DIAL_RESULT_RINGING:
04889       case AST_DIAL_RESULT_PROGRESS:
04890       case AST_DIAL_RESULT_PROCEEDING:
04891          break;
04892       }
04893       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
04894          /* Queue up reprocessing ringing trunks, and then ringing stations again */
04895          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04896          sla_queue_event(SLA_EVENT_DIAL_STATE);
04897          break;
04898       }
04899    }
04900    AST_LIST_TRAVERSE_SAFE_END;
04901 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 5149 of file app_meetme.c.

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

Referenced by sla_thread().

05150 {
05151    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
05152    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
05153    ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
05154       event->station->name, event->trunk_ref->trunk->name);
05155    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
05156       INACTIVE_TRUNK_REFS, event->trunk_ref);
05157 
05158    if (event->trunk_ref->trunk->active_stations == 1) {
05159       /* The station putting it on hold is the only one on the call, so start
05160        * Music on hold to the trunk. */
05161       event->trunk_ref->trunk->on_hold = 1;
05162       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
05163    }
05164 
05165    ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
05166    event->trunk_ref->chan = NULL;
05167 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 5139 of file app_meetme.c.

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

Referenced by sla_thread().

05140 {
05141    ast_mutex_lock(&sla.lock);
05142    sla_ring_stations();
05143    ast_mutex_unlock(&sla.lock);
05144 
05145    /* Find stations that shouldn't be ringing anymore. */
05146    sla_hangup_stations();
05147 }

static void sla_hangup_stations ( void   )  [static]

Definition at line 5111 of file app_meetme.c.

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

Referenced by sla_handle_ringing_trunk_event().

05112 {
05113    struct sla_trunk_ref *trunk_ref;
05114    struct sla_ringing_station *ringing_station;
05115 
05116    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05117       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05118          struct sla_ringing_trunk *ringing_trunk;
05119          ast_mutex_lock(&sla.lock);
05120          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05121             if (trunk_ref->trunk == ringing_trunk->trunk)
05122                break;
05123          }
05124          ast_mutex_unlock(&sla.lock);
05125          if (ringing_trunk)
05126             break;
05127       }
05128       if (!trunk_ref) {
05129          AST_LIST_REMOVE_CURRENT(entry);
05130          ast_dial_join(ringing_station->station->dial);
05131          ast_dial_destroy(ringing_station->station->dial);
05132          ringing_station->station->dial = NULL;
05133          ast_free(ringing_station);
05134       }
05135    }
05136    AST_LIST_TRAVERSE_SAFE_END
05137 }

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

Definition at line 1452 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01453 {
01454    const char *hold = "Unknown";
01455 
01456    switch (hold_access) {
01457    case SLA_HOLD_OPEN:
01458       hold = "Open";
01459       break;
01460    case SLA_HOLD_PRIVATE:
01461       hold = "Private";
01462    default:
01463       break;
01464    }
01465 
01466    return hold;
01467 }

static int sla_load_config ( int  reload  )  [static]

Definition at line 6285 of file app_meetme.c.

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

Referenced by load_config(), and sla_check_reload().

06286 {
06287    struct ast_config *cfg;
06288    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06289    const char *cat = NULL;
06290    int res = 0;
06291    const char *val;
06292 
06293    if (!reload) {
06294       ast_mutex_init(&sla.lock);
06295       ast_cond_init(&sla.cond, NULL);
06296    }
06297 
06298    if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
06299       return 0; /* Treat no config as normal */
06300    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06301       return 0;
06302    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06303       ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format.  Aborting.\n");
06304       return 0;
06305    }
06306 
06307    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
06308       sla.attempt_callerid = ast_true(val);
06309 
06310    while ((cat = ast_category_browse(cfg, cat)) && !res) {
06311       const char *type;
06312       if (!strcasecmp(cat, "general"))
06313          continue;
06314       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
06315          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
06316             SLA_CONFIG_FILE);
06317          continue;
06318       }
06319       if (!strcasecmp(type, "trunk"))
06320          res = sla_build_trunk(cfg, cat);
06321       else if (!strcasecmp(type, "station"))
06322          res = sla_build_station(cfg, cat);
06323       else {
06324          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
06325             SLA_CONFIG_FILE, type);
06326       }
06327    }
06328 
06329    ast_config_destroy(cfg);
06330 
06331    if (!reload && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations)))
06332       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
06333 
06334    return res;
06335 }

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

05328 {
05329    unsigned int timeout = UINT_MAX;
05330    struct timeval wait;
05331    unsigned int change_made = 0;
05332 
05333    /* Check for ring timeouts on ringing trunks */
05334    if (sla_calc_trunk_timeouts(&timeout))
05335       change_made = 1;
05336 
05337    /* Check for ring timeouts on ringing stations */
05338    if (sla_calc_station_timeouts(&timeout))
05339       change_made = 1;
05340 
05341    /* Check for station ring delays */
05342    if (sla_calc_station_delays(&timeout))
05343       change_made = 1;
05344 
05345    /* queue reprocessing of ringing trunks */
05346    if (change_made)
05347       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
05348 
05349    /* No timeout */
05350    if (timeout == UINT_MAX)
05351       return 0;
05352 
05353    if (ts) {
05354       wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
05355       ts->tv_sec = wait.tv_sec;
05356       ts->tv_nsec = wait.tv_usec * 1000;
05357    }
05358 
05359    return 1;
05360 }

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

Queue a SLA event from the conference.

Definition at line 1762 of file app_meetme.c.

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

Referenced by conf_run().

01764 {
01765    struct sla_station *station;
01766    struct sla_trunk_ref *trunk_ref = NULL;
01767    char *trunk_name;
01768 
01769    trunk_name = ast_strdupa(conf->confno);
01770    strsep(&trunk_name, "_");
01771    if (ast_strlen_zero(trunk_name)) {
01772       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01773       return;
01774    }
01775 
01776    AST_RWLIST_RDLOCK(&sla_stations);
01777    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01778       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01779          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01780             break;
01781       }
01782       if (trunk_ref)
01783          break;
01784    }
01785    AST_RWLIST_UNLOCK(&sla_stations);
01786 
01787    if (!trunk_ref) {
01788       ast_debug(1, "Trunk not found for event!\n");
01789       return;
01790    }
01791 
01792    sla_queue_event_full(type, trunk_ref, station, 1);
01793 }

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

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

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

01726 {
01727    struct sla_event *event;
01728 
01729    if (sla.thread == AST_PTHREADT_NULL) {
01730       return;
01731    }
01732 
01733    if (!(event = ast_calloc(1, sizeof(*event))))
01734       return;
01735 
01736    event->type = type;
01737    event->trunk_ref = trunk_ref;
01738    event->station = station;
01739 
01740    if (!lock) {
01741       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01742       return;
01743    }
01744 
01745    ast_mutex_lock(&sla.lock);
01746    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01747    ast_cond_signal(&sla.cond);
01748    ast_mutex_unlock(&sla.lock);
01749 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1751 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01752 {
01753    sla_queue_event_full(type, NULL, NULL, 0);
01754 }

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 4944 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_strlen_zero(), ast_tvnow(), sla_trunk::chan, ast_channel::cid, ast_callerid::cid_name, cid_name, ast_callerid::cid_num, cid_num, sla_station::device, sla_station::dial, sla_failed_station::last_try, sla, sla_create_ringing_station(), sla_dial_state_callback(), sla_failed_station::station, and sla_ringing_trunk::trunk.

Referenced by sla_ring_stations().

04945 {
04946    char *tech, *tech_data;
04947    struct ast_dial *dial;
04948    struct sla_ringing_station *ringing_station;
04949    const char *cid_name = NULL, *cid_num = NULL;
04950    enum ast_dial_result res;
04951 
04952    if (!(dial = ast_dial_create()))
04953       return -1;
04954 
04955    ast_dial_set_state_callback(dial, sla_dial_state_callback);
04956    tech_data = ast_strdupa(station->device);
04957    tech = strsep(&tech_data, "/");
04958 
04959    if (ast_dial_append(dial, tech, tech_data) == -1) {
04960       ast_dial_destroy(dial);
04961       return -1;
04962    }
04963 
04964    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
04965       cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
04966       ast_free(ringing_trunk->trunk->chan->cid.cid_name);
04967       ringing_trunk->trunk->chan->cid.cid_name = NULL;
04968    }
04969    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
04970       cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
04971       ast_free(ringing_trunk->trunk->chan->cid.cid_num);
04972       ringing_trunk->trunk->chan->cid.cid_num = NULL;
04973    }
04974 
04975    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
04976    
04977    if (cid_name)
04978       ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
04979    if (cid_num)
04980       ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
04981    
04982    if (res != AST_DIAL_RESULT_TRYING) {
04983       struct sla_failed_station *failed_station;
04984       ast_dial_destroy(dial);
04985       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
04986          return -1;
04987       failed_station->station = station;
04988       failed_station->last_try = ast_tvnow();
04989       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
04990       return -1;
04991    }
04992    if (!(ringing_station = sla_create_ringing_station(station))) {
04993       ast_dial_join(dial);
04994       ast_dial_destroy(dial);
04995       return -1;
04996    }
04997 
04998    station->dial = dial;
04999 
05000    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
05001 
05002    return 0;
05003 }

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

References AST_LIST_TRAVERSE, sla, sla_check_failed_station(), sla_check_inuse_station(), sla_check_ringing_station(), sla_check_station_delay(), sla_check_timed_out_station(), sla_ring_station(), sla_station_ref::station, sla_trunk::stations, and sla_ringing_trunk::trunk.

Referenced by sla_handle_ringing_trunk_event().

05071 {
05072    struct sla_station_ref *station_ref;
05073    struct sla_ringing_trunk *ringing_trunk;
05074 
05075    /* Make sure that every station that uses at least one of the ringing
05076     * trunks, is ringing. */
05077    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05078       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
05079          int time_left;
05080 
05081          /* Is this station already ringing? */
05082          if (sla_check_ringing_station(station_ref->station))
05083             continue;
05084 
05085          /* Is this station already in a call? */
05086          if (sla_check_inuse_station(station_ref->station))
05087             continue;
05088 
05089          /* Did we fail to dial this station earlier?  If so, has it been
05090           * a minute since we tried? */
05091          if (sla_check_failed_station(station_ref->station))
05092             continue;
05093 
05094          /* If this station already timed out while this trunk was ringing,
05095           * do not dial it again for this ringing trunk. */
05096          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
05097             continue;
05098 
05099          /* Check for a ring delay in progress */
05100          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
05101          if (time_left != INT_MAX && time_left > 0)
05102             continue;
05103 
05104          /* It is time to make this station begin to ring.  Do it! */
05105          sla_ring_station(ringing_trunk, station_ref->station);
05106       }
05107    }
05108    /* Now, all of the stations that should be ringing, are ringing. */
05109 }

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

Definition at line 1534 of file app_meetme.c.

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

01535 {
01536    const struct sla_station *station;
01537 
01538    switch (cmd) {
01539    case CLI_INIT:
01540       e->command = "sla show stations";
01541       e->usage =
01542          "Usage: sla show stations\n"
01543          "       This will list all stations defined in sla.conf\n";
01544       return NULL;
01545    case CLI_GENERATE:
01546       return NULL;
01547    }
01548 
01549    ast_cli(a->fd, "\n" 
01550                "=============================================================\n"
01551                "=== Configured SLA Stations =================================\n"
01552                "=============================================================\n"
01553                "===\n");
01554    AST_RWLIST_RDLOCK(&sla_stations);
01555    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01556       struct sla_trunk_ref *trunk_ref;
01557       char ring_timeout[16] = "(none)";
01558       char ring_delay[16] = "(none)";
01559       if (station->ring_timeout) {
01560          snprintf(ring_timeout, sizeof(ring_timeout), 
01561             "%u", station->ring_timeout);
01562       }
01563       if (station->ring_delay) {
01564          snprintf(ring_delay, sizeof(ring_delay), 
01565             "%u", station->ring_delay);
01566       }
01567       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01568                   "=== Station Name:    %s\n"
01569                   "=== ==> Device:      %s\n"
01570                   "=== ==> AutoContext: %s\n"
01571                   "=== ==> RingTimeout: %s\n"
01572                   "=== ==> RingDelay:   %s\n"
01573                   "=== ==> HoldAccess:  %s\n"
01574                   "=== ==> Trunks ...\n",
01575                   station->name, station->device,
01576                   S_OR(station->autocontext, "(none)"), 
01577                   ring_timeout, ring_delay,
01578                   sla_hold_str(station->hold_access));
01579       AST_RWLIST_RDLOCK(&sla_trunks);
01580       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01581          if (trunk_ref->ring_timeout) {
01582             snprintf(ring_timeout, sizeof(ring_timeout),
01583                "%u", trunk_ref->ring_timeout);
01584          } else
01585             strcpy(ring_timeout, "(none)");
01586          if (trunk_ref->ring_delay) {
01587             snprintf(ring_delay, sizeof(ring_delay),
01588                "%u", trunk_ref->ring_delay);
01589          } else
01590             strcpy(ring_delay, "(none)");
01591             ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
01592                      "===       ==> State:       %s\n"
01593                      "===       ==> RingTimeout: %s\n"
01594                      "===       ==> RingDelay:   %s\n",
01595                      trunk_ref->trunk->name,
01596                      trunkstate2str(trunk_ref->state),
01597                      ring_timeout, ring_delay);
01598       }
01599       AST_RWLIST_UNLOCK(&sla_trunks);
01600       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01601                   "===\n");
01602    }
01603    AST_RWLIST_UNLOCK(&sla_stations);
01604    ast_cli(a->fd, "============================================================\n"
01605                "\n");
01606 
01607    return CLI_SUCCESS;
01608 }

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

Definition at line 1469 of file app_meetme.c.

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

01470 {
01471    const struct sla_trunk *trunk;
01472 
01473    switch (cmd) {
01474    case CLI_INIT:
01475       e->command = "sla show trunks";
01476       e->usage =
01477          "Usage: sla show trunks\n"
01478          "       This will list all trunks defined in sla.conf\n";
01479       return NULL;
01480    case CLI_GENERATE:
01481       return NULL;
01482    }
01483 
01484    ast_cli(a->fd, "\n"
01485                "=============================================================\n"
01486                "=== Configured SLA Trunks ===================================\n"
01487                "=============================================================\n"
01488                "===\n");
01489    AST_RWLIST_RDLOCK(&sla_trunks);
01490    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01491       struct sla_station_ref *station_ref;
01492       char ring_timeout[16] = "(none)";
01493       if (trunk->ring_timeout)
01494          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01495       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01496                   "=== Trunk Name:       %s\n"
01497                   "=== ==> Device:       %s\n"
01498                   "=== ==> AutoContext:  %s\n"
01499                   "=== ==> RingTimeout:  %s\n"
01500                   "=== ==> BargeAllowed: %s\n"
01501                   "=== ==> HoldAccess:   %s\n"
01502                   "=== ==> Stations ...\n",
01503                   trunk->name, trunk->device, 
01504                   S_OR(trunk->autocontext, "(none)"), 
01505                   ring_timeout,
01506                   trunk->barge_disabled ? "No" : "Yes",
01507                   sla_hold_str(trunk->hold_access));
01508       AST_RWLIST_RDLOCK(&sla_stations);
01509       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01510          ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
01511       AST_RWLIST_UNLOCK(&sla_stations);
01512       ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
01513    }
01514    AST_RWLIST_UNLOCK(&sla_trunks);
01515    ast_cli(a->fd, "=============================================================\n\n");
01516 
01517    return CLI_SUCCESS;
01518 }

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

Definition at line 5923 of file app_meetme.c.

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

Referenced by load_module().

05924 {
05925    char *buf, *station_name, *trunk_name;
05926    struct sla_station *station;
05927    struct sla_trunk_ref *trunk_ref;
05928    enum ast_device_state res = AST_DEVICE_INVALID;
05929 
05930    trunk_name = buf = ast_strdupa(data);
05931    station_name = strsep(&trunk_name, "_");
05932 
05933    AST_RWLIST_RDLOCK(&sla_stations);
05934    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05935       if (strcasecmp(station_name, station->name))
05936          continue;
05937       AST_RWLIST_RDLOCK(&sla_trunks);
05938       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05939          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
05940             break;
05941       }
05942       if (!trunk_ref) {
05943          AST_RWLIST_UNLOCK(&sla_trunks);
05944          break;
05945       }
05946       res = sla_state_to_devstate(trunk_ref->state);
05947       AST_RWLIST_UNLOCK(&sla_trunks);
05948    }
05949    AST_RWLIST_UNLOCK(&sla_stations);
05950 
05951    if (res == AST_DEVICE_INVALID) {
05952       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
05953          trunk_name, station_name);
05954    }
05955 
05956    return res;
05957 }

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

Definition at line 5601 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_strlen_zero(), build_conf(), sla_trunk_ref::chan, sla_trunk::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_SLA_STATION, dial_trunk(), dispose_conf(), ast_flags::flags, free, sla_trunk::hold_stations, LOG_NOTICE, LOG_WARNING, MAX_CONFNUM, sla_trunk::name, sla_station::name, sla_trunk::on_hold, pbx_builtin_setvar_helper(), sla_station::ref_count, sla, sla_change_trunk_state(), sla_choose_idle_trunk(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_DIAL_STATE, SLA_EVENT_RINGING_TRUNK, sla_find_station(), sla_find_trunk_ref_byname(), sla_queue_event(), SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, sla_trunk_ref::state, sla_ringing_trunk::trunk, sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.

Referenced by load_module().

05602 {
05603    char *station_name, *trunk_name;
05604    struct sla_station *station;
05605    struct sla_trunk_ref *trunk_ref = NULL;
05606    char conf_name[MAX_CONFNUM];
05607    struct ast_flags conf_flags = { 0 };
05608    struct ast_conference *conf;
05609 
05610    if (ast_strlen_zero(data)) {
05611       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05612       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05613       return 0;
05614    }
05615 
05616    trunk_name = ast_strdupa(data);
05617    station_name = strsep(&trunk_name, "_");
05618 
05619    if (ast_strlen_zero(station_name)) {
05620       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05621       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05622       return 0;
05623    }
05624 
05625    AST_RWLIST_RDLOCK(&sla_stations);
05626    station = sla_find_station(station_name);
05627    if (station)
05628       ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
05629    AST_RWLIST_UNLOCK(&sla_stations);
05630 
05631    if (!station) {
05632       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
05633       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05634       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05635       return 0;
05636    }
05637 
05638    AST_RWLIST_RDLOCK(&sla_trunks);
05639    if (!ast_strlen_zero(trunk_name)) {
05640       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
05641    } else
05642       trunk_ref = sla_choose_idle_trunk(station);
05643    AST_RWLIST_UNLOCK(&sla_trunks);
05644 
05645    if (!trunk_ref) {
05646       if (ast_strlen_zero(trunk_name))
05647          ast_log(LOG_NOTICE, "No trunks available for call.\n");
05648       else {
05649          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
05650             "'%s' due to access controls.\n", trunk_name);
05651       }
05652       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05653       ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05654       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05655       return 0;
05656    }
05657 
05658    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
05659       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
05660          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05661       else {
05662          trunk_ref->state = SLA_TRUNK_STATE_UP;
05663          ast_devstate_changed(AST_DEVICE_INUSE, 
05664             "SLA:%s_%s", station->name, trunk_ref->trunk->name);
05665       }
05666    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
05667       struct sla_ringing_trunk *ringing_trunk;
05668 
05669       ast_mutex_lock(&sla.lock);
05670       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05671          if (ringing_trunk->trunk == trunk_ref->trunk) {
05672             AST_LIST_REMOVE_CURRENT(entry);
05673             break;
05674          }
05675       }
05676       AST_LIST_TRAVERSE_SAFE_END
05677       ast_mutex_unlock(&sla.lock);
05678 
05679       if (ringing_trunk) {
05680          answer_trunk_chan(ringing_trunk->trunk->chan);
05681          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05682 
05683          free(ringing_trunk);
05684 
05685          /* Queue up reprocessing ringing trunks, and then ringing stations again */
05686          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05687          sla_queue_event(SLA_EVENT_DIAL_STATE);
05688       }
05689    }
05690 
05691    trunk_ref->chan = chan;
05692 
05693    if (!trunk_ref->trunk->chan) {
05694       ast_mutex_t cond_lock;
05695       ast_cond_t cond;
05696       pthread_t dont_care;
05697       struct dial_trunk_args args = {
05698          .trunk_ref = trunk_ref,
05699          .station = station,
05700          .cond_lock = &cond_lock,
05701          .cond = &cond,
05702       };
05703       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05704       /* Create a thread to dial the trunk and dump it into the conference.
05705        * However, we want to wait until the trunk has been dialed and the
05706        * conference is created before continuing on here. */
05707       ast_autoservice_start(chan);
05708       ast_mutex_init(&cond_lock);
05709       ast_cond_init(&cond, NULL);
05710       ast_mutex_lock(&cond_lock);
05711       ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
05712       ast_cond_wait(&cond, &cond_lock);
05713       ast_mutex_unlock(&cond_lock);
05714       ast_mutex_destroy(&cond_lock);
05715       ast_cond_destroy(&cond);
05716       ast_autoservice_stop(chan);
05717       if (!trunk_ref->trunk->chan) {
05718          ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
05719          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05720          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05721          trunk_ref->chan = NULL;
05722          ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05723          sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05724          return 0;
05725       }
05726    }
05727 
05728    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
05729       trunk_ref->trunk->on_hold) {
05730       trunk_ref->trunk->on_hold = 0;
05731       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
05732       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05733    }
05734 
05735    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05736    ast_set_flag(&conf_flags, 
05737       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05738    ast_answer(chan);
05739    conf = build_conf(conf_name, "", "", 0, 0, 1, chan);
05740    if (conf) {
05741       conf_run(chan, conf, conf_flags.flags, NULL);
05742       dispose_conf(conf);
05743       conf = NULL;
05744    }
05745    trunk_ref->chan = NULL;
05746    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05747       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05748       strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
05749       admin_exec(NULL, conf_name);
05750       trunk_ref->trunk->hold_stations = 0;
05751       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05752    }
05753    
05754    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
05755 
05756    ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05757    sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05758 
05759    return 0;
05760 }

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

Definition at line 4734 of file app_meetme.c.

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

Referenced by sla_calc_station_timeouts(), and sla_handle_dial_state_event().

04736 {
04737    struct sla_ringing_trunk *ringing_trunk;
04738    struct sla_trunk_ref *trunk_ref;
04739    struct sla_station_ref *station_ref;
04740 
04741    ast_dial_join(ringing_station->station->dial);
04742    ast_dial_destroy(ringing_station->station->dial);
04743    ringing_station->station->dial = NULL;
04744 
04745    if (hangup == SLA_STATION_HANGUP_NORMAL)
04746       goto done;
04747 
04748    /* If the station is being hung up because of a timeout, then add it to the
04749     * list of timed out stations on each of the ringing trunks.  This is so
04750     * that when doing further processing to figure out which stations should be
04751     * ringing, which trunk to answer, determining timeouts, etc., we know which
04752     * ringing trunks we should ignore. */
04753    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04754       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04755          if (ringing_trunk->trunk == trunk_ref->trunk)
04756             break;
04757       }
04758       if (!trunk_ref)
04759          continue;
04760       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
04761          continue;
04762       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
04763    }
04764 
04765 done:
04766    ast_free(ringing_station);
04767 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 4719 of file app_meetme.c.

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

Referenced by sla_calc_trunk_timeouts().

04720 {
04721    char buf[80];
04722    struct sla_station_ref *station_ref;
04723 
04724    snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
04725    admin_exec(NULL, buf);
04726    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04727 
04728    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
04729       ast_free(station_ref);
04730 
04731    ast_free(ringing_trunk);
04732 }

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

Definition at line 5407 of file app_meetme.c.

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

Referenced by sla_load_config().

05408 {
05409    struct sla_failed_station *failed_station;
05410    struct sla_ringing_station *ringing_station;
05411 
05412    ast_mutex_lock(&sla.lock);
05413 
05414    while (!sla.stop) {
05415       struct sla_event *event;
05416       struct timespec ts = { 0, };
05417       unsigned int have_timeout = 0;
05418 
05419       if (AST_LIST_EMPTY(&sla.event_q)) {
05420          if ((have_timeout = sla_process_timers(&ts)))
05421             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
05422          else
05423             ast_cond_wait(&sla.cond, &sla.lock);
05424          if (sla.stop)
05425             break;
05426       }
05427 
05428       if (have_timeout)
05429          sla_process_timers(NULL);
05430 
05431       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
05432          ast_mutex_unlock(&sla.lock);
05433          switch (event->type) {
05434          case SLA_EVENT_HOLD:
05435             sla_handle_hold_event(event);
05436             break;
05437          case SLA_EVENT_DIAL_STATE:
05438             sla_handle_dial_state_event();
05439             break;
05440          case SLA_EVENT_RINGING_TRUNK:
05441             sla_handle_ringing_trunk_event();
05442             break;
05443          case SLA_EVENT_RELOAD:
05444             sla.reload = 1;
05445          case SLA_EVENT_CHECK_RELOAD:
05446             break;
05447          }
05448          ast_free(event);
05449          ast_mutex_lock(&sla.lock);
05450       }
05451 
05452       if (sla.reload)
05453          sla_check_reload();
05454    }
05455 
05456    ast_mutex_unlock(&sla.lock);
05457 
05458    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
05459       ast_free(ringing_station);
05460 
05461    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
05462       ast_free(failed_station);
05463 
05464    return NULL;
05465 }

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

Definition at line 5808 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_strlen_zero(), ast_test_flag, build_conf(), sla_trunk::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, dispose_conf(), ast_flags::flags, LOG_ERROR, MAX_CONFNUM, sla_trunk::on_hold, OPT_ARG_ARRAY_SIZE, OPT_ARG_MOH_CLASS, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), queue_ringing_trunk(), sla_trunk::ref_count, sla, sla_change_trunk_state(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), SLA_TRUNK_OPT_ARG_ARRAY_SIZE, SLA_TRUNK_OPT_ARG_MOH_CLASS, SLA_TRUNK_OPT_MOH, sla_trunk_opts, SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by load_module().

05809 {
05810    char conf_name[MAX_CONFNUM];
05811    struct ast_conference *conf;
05812    struct ast_flags conf_flags = { 0 };
05813    struct sla_trunk *trunk;
05814    struct sla_ringing_trunk *ringing_trunk;
05815    AST_DECLARE_APP_ARGS(args,
05816       AST_APP_ARG(trunk_name);
05817       AST_APP_ARG(options);
05818    );
05819    char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
05820    char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
05821    struct ast_flags opt_flags = { 0 };
05822    char *parse;
05823 
05824    if (ast_strlen_zero(data)) {
05825       ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
05826       return -1;
05827    }
05828 
05829    parse = ast_strdupa(data);
05830    AST_STANDARD_APP_ARGS(args, parse);
05831    if (args.argc == 2) {
05832       if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
05833          ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
05834          return -1;
05835       }
05836    }
05837 
05838    AST_RWLIST_RDLOCK(&sla_trunks);
05839    trunk = sla_find_trunk(args.trunk_name);
05840    if (trunk)
05841       ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
05842    AST_RWLIST_UNLOCK(&sla_trunks);
05843 
05844    if (!trunk) {
05845       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
05846       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05847       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05848       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05849       return 0;
05850    }
05851 
05852    if (trunk->chan) {
05853       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
05854          args.trunk_name);
05855       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05856       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05857       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05858       return 0;
05859    }
05860 
05861    trunk->chan = chan;
05862 
05863    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
05864       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05865       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05866       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05867       return 0;
05868    }
05869 
05870    snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
05871    conf = build_conf(conf_name, "", "", 1, 1, 1, chan);
05872    if (!conf) {
05873       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05874       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05875       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05876       return 0;
05877    }
05878    ast_set_flag(&conf_flags, 
05879       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
05880 
05881    if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
05882       ast_indicate(chan, -1);
05883       ast_set_flag(&conf_flags, CONFFLAG_MOH);
05884       conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
05885    } else
05886       ast_indicate(chan, AST_CONTROL_RINGING);
05887 
05888    conf_run(chan, conf, conf_flags.flags, opts);
05889    dispose_conf(conf);
05890    conf = NULL;
05891    trunk->chan = NULL;
05892    trunk->on_hold = 0;
05893 
05894    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05895 
05896    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
05897       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
05898 
05899    /* Remove the entry from the list of ringing trunks if it is still there. */
05900    ast_mutex_lock(&sla.lock);
05901    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05902       if (ringing_trunk->trunk == trunk) {
05903          AST_LIST_REMOVE_CURRENT(entry);
05904          break;
05905       }
05906    }
05907    AST_LIST_TRAVERSE_SAFE_END;
05908    ast_mutex_unlock(&sla.lock);
05909    if (ringing_trunk) {
05910       ast_free(ringing_trunk);
05911       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
05912       /* Queue reprocessing of ringing trunks to make stations stop ringing
05913        * that shouldn't be ringing after this trunk stopped. */
05914       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05915    }
05916 
05917    ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05918    sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05919 
05920    return 0;
05921 }

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

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

01521 {
01522 #define S(e) case e: return # e;
01523    switch (state) {
01524    S(SLA_TRUNK_STATE_IDLE)
01525    S(SLA_TRUNK_STATE_RINGING)
01526    S(SLA_TRUNK_STATE_UP)
01527    S(SLA_TRUNK_STATE_ONHOLD)
01528    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01529    }
01530    return "Uknown State";
01531 #undef S
01532 }

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

Definition at line 993 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

00994 {
00995    tweak_volume(&user->listen, action);
00996    /* attempt to make the adjustment in the channel driver;
00997       if successful, don't adjust in the frame reading routine
00998    */
00999    if (!set_listen_volume(user, user->listen.desired))
01000       user->listen.actual = 0;
01001    else
01002       user->listen.actual = user->listen.desired;
01003 }

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

Definition at line 981 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

00982 {
00983    tweak_volume(&user->talk, action);
00984    /* attempt to make the adjustment in the channel driver;
00985       if successful, don't adjust in the frame reading routine
00986    */
00987    if (!set_talk_volume(user, user->talk.desired))
00988       user->talk.actual = 0;
00989    else
00990       user->talk.actual = user->talk.desired;
00991 }

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

Definition at line 946 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

00947 {
00948    switch (action) {
00949    case VOL_UP:
00950       switch (vol->desired) { 
00951       case 5:
00952          break;
00953       case 0:
00954          vol->desired = 2;
00955          break;
00956       case -2:
00957          vol->desired = 0;
00958          break;
00959       default:
00960          vol->desired++;
00961          break;
00962       }
00963       break;
00964    case VOL_DOWN:
00965       switch (vol->desired) {
00966       case -5:
00967          break;
00968       case 2:
00969          vol->desired = 0;
00970          break;
00971       case 0:
00972          vol->desired = -2;
00973          break;
00974       default:
00975          vol->desired--;
00976          break;
00977       }
00978    }
00979 }

static int unload_module ( void   )  [static]

Definition at line 6435 of file app_meetme.c.

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

06436 {
06437    int res = 0;
06438    
06439    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
06440    res = ast_manager_unregister("MeetmeMute");
06441    res |= ast_manager_unregister("MeetmeUnmute");
06442    res |= ast_manager_unregister("MeetmeList");
06443    res |= ast_unregister_application(app4);
06444    res |= ast_unregister_application(app3);
06445    res |= ast_unregister_application(app2);
06446    res |= ast_unregister_application(app);
06447    res |= ast_unregister_application(slastation_app);
06448    res |= ast_unregister_application(slatrunk_app);
06449 
06450    ast_devstate_prov_del("Meetme");
06451    ast_devstate_prov_del("SLA");
06452    
06453    sla_destroy();
06454    
06455    res |= ast_custom_function_unregister(&meetme_info_acf);
06456    ast_unload_realtime("meetme");
06457 
06458    return res;
06459 }


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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 6500 of file app_meetme.c.

const char* app = "MeetMe" [static]

Definition at line 568 of file app_meetme.c.

const char* app2 = "MeetMeCount" [static]

Definition at line 569 of file app_meetme.c.

const char* app3 = "MeetMeAdmin" [static]

Definition at line 570 of file app_meetme.c.

const char* app4 = "MeetMeChannelAdmin" [static]

Definition at line 571 of file app_meetme.c.

Definition at line 6500 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 850 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 859 of file app_meetme.c.

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1610 of file app_meetme.c.

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

Definition at line 652 of file app_meetme.c.

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

int earlyalert [static]

Definition at line 578 of file app_meetme.c.

int endalert [static]

Definition at line 579 of file app_meetme.c.

struct { ... } event_q
int extendby [static]

Definition at line 580 of file app_meetme.c.

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

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

struct sla_event* last
char mandescr_meetmelist[] [static]

Definition at line 4284 of file app_meetme.c.

Definition at line 6406 of file app_meetme.c.

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

Definition at line 566 of file app_meetme.c.

Referenced by conf_exec().

static int reload

A reload has been requested

reload: Part of Asterisk module interface ---

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

int rt_schedule [static]

Definition at line 576 of file app_meetme.c.

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

Definition at line 5806 of file app_meetme.c.

Referenced by sla_trunk_exec().

const char* slastation_app = "SLAStation" [static]

Definition at line 572 of file app_meetme.c.

const char* slatrunk_app = "SLATrunk" [static]

Definition at line 573 of file app_meetme.c.

unsigned int stop

Definition at line 847 of file app_meetme.c.

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

pthread_t thread

Generated by  doxygen 1.6.2