Thu Jul 9 13:40:45 2009

Asterisk developer's documentation


app_meetme.c File Reference

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

#include "asterisk.h"
#include <sys/ioctl.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/astobj.h"
#include "asterisk/astobj2.h"
#include "asterisk/devicestate.h"
#include "asterisk/dial.h"
#include "asterisk/causes.h"
#include "asterisk/paths.h"
#include "enter.h"
#include "leave.h"

Go to the source code of this file.

Data Structures

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

Defines

#define AST_FRAME_BITS   32
#define CONF_SIZE   320
#define CONFIG_FILE_NAME   "meetme.conf"
#define DATE_FORMAT   "%Y-%m-%d %H:%M:%S"
#define DEFAULT_AUDIO_BUFFERS   32
#define MAX_CONFNUM   80
#define MAX_PIN   80
#define MC_DATA_FORMAT   "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
#define MC_HEADER_FORMAT   "%-14s %-14s %-10s %-8s %-8s %-6s\n"
#define MEETME_DELAYDETECTENDTALK   1000
#define MEETME_DELAYDETECTTALK   300
#define S(e)   case e: return # e;
#define SLA_CONFIG_FILE   "sla.conf"

Enumerations

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int action_meetmelist (struct mansession *s, const struct message *m)
static int action_meetmemute (struct mansession *s, const struct message *m)
static int action_meetmeunmute (struct mansession *s, const struct message *m)
static int admin_exec (struct ast_channel *chan, void *data)
 The MeetMeadmin application.
static void * announce_thread (void *data)
static void answer_trunk_chan (struct ast_channel *chan)
static struct ast_conferencebuild_conf (char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan)
 Find or create a conference.
static int can_write (struct ast_channel *chan, int confflags)
static int careful_write (int fd, unsigned char *data, int len, int block)
static int channel_admin_exec (struct ast_channel *chan, void *data)
static char * complete_meetmecmd (const char *line, const char *word, int pos, int state)
static int conf_exec (struct ast_channel *chan, void *data)
 The meetme() application.
static void conf_flush (int fd, struct ast_channel *chan)
static int conf_free (struct ast_conference *conf)
static void conf_play (struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
static void conf_queue_dtmf (const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
static int conf_run (struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
static void conf_start_moh (struct ast_channel *chan, const char *musicclass)
static int count_exec (struct ast_channel *chan, void *data)
 The MeetmeCount application.
static struct sla_trunk_refcreate_trunk_ref (struct sla_trunk *trunk)
static void destroy_station (struct sla_station *station)
static void destroy_trunk (struct sla_trunk *trunk)
static void * dial_trunk (void *data)
static int dispose_conf (struct ast_conference *conf)
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
static struct ast_conferencefind_conf_realtime (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags, char *optargs[], int *too_early)
static struct ast_conf_userfind_user (struct ast_conference *conf, char *callerident)
static const char * get_announce_filename (enum announcetypes type)
static char * istalking (int x)
static int load_config (int reload)
static void load_config_meetme (void)
static int load_module (void)
static char * meetme_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int meetmemute (struct mansession *s, const struct message *m, int mute)
static enum ast_device_state meetmestate (const char *data)
 Callback for devicestate providers.
static struct sla_ringing_trunkqueue_ringing_trunk (struct sla_trunk *trunk)
static void * recordthread (void *args)
static int reload (void)
static void reset_volumes (struct ast_conf_user *user)
static void * run_station (void *data)
static int set_listen_volume (struct ast_conf_user *user, int volume)
static int set_talk_volume (struct ast_conf_user *user, int volume)
static void sla_add_trunk_to_station (struct sla_station *station, struct ast_variable *var)
static int sla_build_station (struct ast_config *cfg, const char *cat)
static int sla_build_trunk (struct ast_config *cfg, const char *cat)
static int sla_calc_station_delays (unsigned int *timeout)
 Calculate the ring delay for a station.
static int sla_calc_station_timeouts (unsigned int *timeout)
 Process station ring timeouts.
static int sla_calc_trunk_timeouts (unsigned int *timeout)
 Process trunk ring timeouts.
static void sla_change_trunk_state (const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
static int sla_check_device (const char *device)
static int sla_check_failed_station (const struct sla_station *station)
 Check to see if this station has failed to be dialed in the past minute.
static int sla_check_inuse_station (const struct sla_station *station)
 Check to see if a station is in use.
static void sla_check_reload (void)
 Check if we can do a reload of SLA, and do it if we can.
static int sla_check_ringing_station (const struct sla_station *station)
 Check to see if this station is already ringing.
static int sla_check_station_delay (struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
 Calculate the ring delay for a given ringing trunk on a station.
static int sla_check_station_hold_access (const struct sla_trunk *trunk, const struct sla_station *station)
static int sla_check_timed_out_station (const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
 Check to see if dialing this station already timed out for this ringing trunk.
static struct sla_trunk_refsla_choose_idle_trunk (const struct sla_station *station)
 For a given station, choose the highest priority idle trunk.
static struct sla_ringing_trunksla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int remove)
 Choose the highest priority ringing trunk for a station.
static struct sla_ringing_stationsla_create_ringing_station (struct sla_station *station)
static struct sla_station_refsla_create_station_ref (struct sla_station *station)
static void sla_destroy (void)
static void sla_dial_state_callback (struct ast_dial *dial)
static struct sla_stationsla_find_station (const char *name)
 Find an SLA station by name.
static struct sla_trunksla_find_trunk (const char *name)
 Find an SLA trunk by name.
static struct sla_trunk_refsla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk)
static struct sla_trunk_refsla_find_trunk_ref_byname (const struct sla_station *station, const char *name)
 Find a trunk reference on a station by name.
static void sla_handle_dial_state_event (void)
static void sla_handle_hold_event (struct sla_event *event)
static void sla_handle_ringing_trunk_event (void)
static void sla_hangup_stations (void)
static const char * sla_hold_str (unsigned int hold_access)
static int sla_load_config (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 = "068e67f60f50dd9ee86464c05884a49d" , .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 const struct ast_module_infoast_module_info = &__mod_info
static int audio_buffers
static struct ast_cli_entry cli_meetme []
static unsigned int conf_map [1024] = {0, }
static const char * descrip
static const char * descrip2
static const char * descrip3
static const char * descrip4
static int earlyalert
static int endalert
static int fuzzystart
static char const gain_map []
static char mandescr_meetmelist []
static struct ast_app_option meetme_opts [128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
static int rt_log_members
static int rt_schedule
struct {
   unsigned int   attempt_callerid:1
   ast_cond_t   cond
   struct {
      sla_event *   first
      sla_event *   last
   }   event_q
   struct {
      sla_failed_station *   first
      sla_failed_station *   last
   }   failed_stations
   ast_mutex_t   lock
   unsigned int   reload:1
   struct {
      sla_ringing_station *   first
      sla_ringing_station *   last
   }   ringing_stations
   struct {
      sla_ringing_trunk *   first
      sla_ringing_trunk *   last
   }   ringing_trunks
   unsigned int   stop:1
   pthread_t   thread
sla
 A structure for data used by the sla thread.
static const char sla_registrar [] = "SLA"
static struct ast_app_option sla_trunk_opts [128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, }
static const char * slastation_app = "SLAStation"
static const char * slastation_desc
static const char * slastation_synopsis = "Shared Line Appearance Station"
static const char * slatrunk_app = "SLATrunk"
static const char * slatrunk_desc
static const char * slatrunk_synopsis = "Shared Line Appearance Trunk"
static const char * synopsis = "MeetMe conference bridge"
static const char * synopsis2 = "MeetMe participant count"
static const char * synopsis3 = "MeetMe conference Administration"
static const char * synopsis4 = "MeetMe conference Administration (channel specific)"


Detailed Description

Meet me conference bridge and Shared Line Appearances.

Author:
Mark Spencer <markster@digium.com>

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

Definition in file app_meetme.c.


Define Documentation

#define AST_FRAME_BITS   32

Definition at line 88 of file app_meetme.c.

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

#define CONF_SIZE   320

Definition at line 107 of file app_meetme.c.

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 68 of file app_meetme.c.

Referenced by 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 75 of file app_meetme.c.

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

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 72 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

Definition at line 361 of file app_meetme.c.

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

#define MAX_PIN   80

Definition at line 362 of file app_meetme.c.

Referenced by conf_exec().

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

Referenced by meetme_cmd().

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

Referenced by meetme_cmd().

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 86 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 85 of file app_meetme.c.

Referenced by conf_run().

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

Referenced by sms_readfile(), and trunkstate2str().

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 69 of file app_meetme.c.

Referenced by sla_load_config().


Enumeration Type Documentation

anonymous enum

Enumerator:
ADMINFLAG_MUTED  User is muted
ADMINFLAG_SELFMUTED  User muted self
ADMINFLAG_KICKME  User has been kicked
ADMINFLAG_T_REQUEST  User has requested to speak

Definition at line 77 of file app_meetme.c.

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

anonymous enum

Enumerator:
CONFFLAG_ADMIN  user has admin access on the conference
CONFFLAG_MONITOR  If set the user can only receive audio from the conference
CONFFLAG_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 109 of file app_meetme.c.

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

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

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

anonymous enum

Enumerator:
SLA_TRUNK_OPT_MOH 

Definition at line 5154 of file app_meetme.c.

05154      {
05155    SLA_TRUNK_OPT_MOH = (1 << 0),
05156 };

anonymous enum

Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 5158 of file app_meetme.c.

05158      {
05159    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
05160    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
05161 };

enum announcetypes

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 364 of file app_meetme.c.

00364                    {
00365    CONF_HASJOIN,
00366    CONF_HASLEFT
00367 };

enum entrance_sound

Enumerator:
ENTER 
LEAVE 

Definition at line 95 of file app_meetme.c.

00095                     {
00096    ENTER,
00097    LEAVE
00098 };

enum recording_state

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 100 of file app_meetme.c.

enum sla_event_type

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

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

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

enum sla_hold_access

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

Definition at line 464 of file app_meetme.c.

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

enum sla_station_hangup

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 591 of file app_meetme.c.

enum sla_trunk_state

Enumerator:
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 456 of file app_meetme.c.

enum sla_which_trunk_refs

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 451 of file app_meetme.c.

00451                           {
00452    ALL_TRUNK_REFS,
00453    INACTIVE_TRUNK_REFS,
00454 };

enum volume_action

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 90 of file app_meetme.c.

00090                    {
00091    VOL_UP,
00092    VOL_DOWN
00093 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 5766 of file app_meetme.c.

static void __unreg_module ( void   )  [static]

Definition at line 5766 of file app_meetme.c.

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

Definition at line 3663 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_error(), astman_send_listack(), CONFFLAG_ADMIN, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_conference::confno, ast_conf_user::list, s, S_OR, total, user, and ast_conference::userlist.

Referenced by load_module().

03664 {
03665    const char *actionid = astman_get_header(m, "ActionID");
03666    const char *conference = astman_get_header(m, "Conference");
03667    char idText[80] = "";
03668    struct ast_conference *cnf;
03669    struct ast_conf_user *user;
03670    int total = 0;
03671 
03672    if (!ast_strlen_zero(actionid))
03673       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
03674 
03675    if (AST_LIST_EMPTY(&confs)) {
03676       astman_send_error(s, m, "No active conferences.");
03677       return 0;
03678    }
03679 
03680    astman_send_listack(s, m, "Meetme user list will follow", "start");
03681 
03682    /* Find the right conference */
03683    AST_LIST_LOCK(&confs);
03684    AST_LIST_TRAVERSE(&confs, cnf, list) {
03685       /* If we ask for one particular, and this isn't it, skip it */
03686       if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
03687          continue;
03688 
03689       /* Show all the users */
03690       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03691          total++;
03692          astman_append(s,
03693          "Event: MeetmeList\r\n"
03694          "%s"
03695          "Conference: %s\r\n"
03696          "UserNumber: %d\r\n"
03697          "CallerIDNum: %s\r\n"
03698          "CallerIDName: %s\r\n"
03699          "Channel: %s\r\n"
03700          "Admin: %s\r\n"
03701          "Role: %s\r\n"
03702          "MarkedUser: %s\r\n"
03703          "Muted: %s\r\n"
03704          "Talking: %s\r\n"
03705          "\r\n",
03706          idText,
03707          cnf->confno,
03708          user->user_no,
03709          S_OR(user->chan->cid.cid_num, "<unknown>"),
03710          S_OR(user->chan->cid.cid_name, "<no name>"),
03711          user->chan->name,
03712          user->userflags & CONFFLAG_ADMIN ? "Yes" : "No",
03713          user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen",
03714          user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No",
03715          user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
03716          user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored"); 
03717       }
03718    }
03719    AST_LIST_UNLOCK(&confs);
03720    /* Send final confirmation */
03721    astman_append(s,
03722    "Event: MeetmeListComplete\r\n"
03723    "EventList: Complete\r\n"
03724    "ListItems: %d\r\n"
03725    "%s"
03726    "\r\n", total, idText);
03727    return 0;
03728 }

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

Definition at line 3645 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03646 {
03647    return meetmemute(s, m, 1);
03648 }

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

Definition at line 3650 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03651 {
03652    return meetmemute(s, m, 0);
03653 }

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

The MeetMeadmin application.

Definition at line 3375 of file app_meetme.c.

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

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

03375                                                             {
03376    char *params;
03377    struct ast_conference *cnf;
03378    struct ast_conf_user *user = NULL;
03379    AST_DECLARE_APP_ARGS(args,
03380       AST_APP_ARG(confno);
03381       AST_APP_ARG(command);
03382       AST_APP_ARG(user);
03383    );
03384 
03385    if (ast_strlen_zero(data)) {
03386       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
03387       return -1;
03388    }
03389 
03390    params = ast_strdupa(data);
03391    AST_STANDARD_APP_ARGS(args, params);
03392 
03393    if (!args.command) {
03394       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
03395       return -1;
03396    }
03397 
03398    AST_LIST_LOCK(&confs);
03399    AST_LIST_TRAVERSE(&confs, cnf, list) {
03400       if (!strcmp(cnf->confno, args.confno))
03401          break;
03402    }
03403 
03404    if (!cnf) {
03405       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
03406       AST_LIST_UNLOCK(&confs);
03407       return 0;
03408    }
03409 
03410    ast_atomic_fetchadd_int(&cnf->refcount, 1);
03411 
03412    if (args.user)
03413       user = find_user(cnf, args.user);
03414 
03415    switch (*args.command) {
03416    case 76: /* L: Lock */ 
03417       cnf->locked = 1;
03418       break;
03419    case 108: /* l: Unlock */ 
03420       cnf->locked = 0;
03421       break;
03422    case 75: /* K: kick all users */
03423       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03424          user->adminflags |= ADMINFLAG_KICKME;
03425       break;
03426    case 101: /* e: Eject last user*/
03427       user = AST_LIST_LAST(&cnf->userlist);
03428       if (!(user->userflags & CONFFLAG_ADMIN))
03429          user->adminflags |= ADMINFLAG_KICKME;
03430       else
03431          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
03432       break;
03433    case 77: /* M: Mute */ 
03434       if (user) {
03435          user->adminflags |= ADMINFLAG_MUTED;
03436       } else
03437          ast_log(LOG_NOTICE, "Specified User not found!\n");
03438       break;
03439    case 78: /* N: Mute all (non-admin) users */
03440       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03441          if (!(user->userflags & CONFFLAG_ADMIN))
03442             user->adminflags |= ADMINFLAG_MUTED;
03443       }
03444       break;               
03445    case 109: /* m: Unmute */ 
03446       if (user) {
03447          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03448       } else
03449          ast_log(LOG_NOTICE, "Specified User not found!\n");
03450       break;
03451    case 110: /* n: Unmute all users */
03452       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03453          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03454       break;
03455    case 107: /* k: Kick user */ 
03456       if (user)
03457          user->adminflags |= ADMINFLAG_KICKME;
03458       else
03459          ast_log(LOG_NOTICE, "Specified User not found!\n");
03460       break;
03461    case 118: /* v: Lower all users listen volume */
03462       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03463          tweak_listen_volume(user, VOL_DOWN);
03464       break;
03465    case 86: /* V: Raise all users listen volume */
03466       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03467          tweak_listen_volume(user, VOL_UP);
03468       break;
03469    case 115: /* s: Lower all users speaking volume */
03470       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03471          tweak_talk_volume(user, VOL_DOWN);
03472       break;
03473    case 83: /* S: Raise all users speaking volume */
03474       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03475          tweak_talk_volume(user, VOL_UP);
03476       break;
03477    case 82: /* R: Reset all volume levels */
03478       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03479          reset_volumes(user);
03480       break;
03481    case 114: /* r: Reset user's volume level */
03482       if (user)
03483          reset_volumes(user);
03484       else
03485          ast_log(LOG_NOTICE, "Specified User not found!\n");
03486       break;
03487    case 85: /* U: Raise user's listen volume */
03488       if (user)
03489          tweak_listen_volume(user, VOL_UP);
03490       else
03491          ast_log(LOG_NOTICE, "Specified User not found!\n");
03492       break;
03493    case 117: /* u: Lower user's listen volume */
03494       if (user)
03495          tweak_listen_volume(user, VOL_DOWN);
03496       else
03497          ast_log(LOG_NOTICE, "Specified User not found!\n");
03498       break;
03499    case 84: /* T: Raise user's talk volume */
03500       if (user)
03501          tweak_talk_volume(user, VOL_UP);
03502       else
03503          ast_log(LOG_NOTICE, "Specified User not found!\n");
03504       break;
03505    case 116: /* t: Lower user's talk volume */
03506       if (user) 
03507          tweak_talk_volume(user, VOL_DOWN);
03508       else 
03509          ast_log(LOG_NOTICE, "Specified User not found!\n");
03510       break;
03511    }
03512 
03513    AST_LIST_UNLOCK(&confs);
03514 
03515    dispose_conf(cnf);
03516    
03517    return 0;
03518 }

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

Definition at line 1542 of file app_meetme.c.

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

Referenced by conf_run().

01543 {
01544    struct announce_listitem *current;
01545    struct ast_conference *conf = data;
01546    int res = 0;
01547    char filename[PATH_MAX] = "";
01548    AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
01549    AST_LIST_HEAD_INIT_NOLOCK(&local_list);
01550 
01551    while (!conf->announcethread_stop) {
01552       ast_mutex_lock(&conf->announcelistlock);
01553       if (conf->announcethread_stop) {
01554          ast_mutex_unlock(&conf->announcelistlock);
01555          break;
01556       }
01557       if (AST_LIST_EMPTY(&conf->announcelist))
01558          ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
01559 
01560       AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
01561       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01562 
01563       ast_mutex_unlock(&conf->announcelistlock);
01564       if (conf->announcethread_stop) {
01565          break;
01566       }
01567 
01568       for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
01569          ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
01570          if (!ast_fileexists(current->namerecloc, NULL, NULL))
01571             continue;
01572          if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
01573             if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
01574                res = ast_waitstream(current->confchan, "");
01575             if (!res) {
01576                ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
01577                if (!ast_streamfile(current->confchan, filename, current->language))
01578                   ast_waitstream(current->confchan, "");
01579             }
01580          }
01581          if (current->announcetype == CONF_HASLEFT) {
01582             ast_filedelete(current->namerecloc, NULL);
01583          }
01584       }
01585    }
01586 
01587    /* thread marked to stop, clean up */
01588    while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
01589       ast_filedelete(current->namerecloc, NULL);
01590       ao2_ref(current, -1);
01591    }
01592    return NULL;
01593 }

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

Definition at line 4027 of file app_meetme.c.

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

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

04028 {
04029    ast_answer(chan);
04030    ast_indicate(chan, -1);
04031 }

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

Find or create a conference.

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

Definition at line 830 of file app_meetme.c.

References ast_atomic_fetchadd_int(), ast_calloc, ast_copy_string(), AST_FORMAT_SLINEAR, ast_free, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), AST_PTHREADT_NULL, ast_request(), ast_set_read_format(), ast_set_write_format(), ast_verb, chan, conf_map, ast_conference::confno, LOG_WARNING, and ast_channel::uniqueid.

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

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

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

Definition at line 1595 of file app_meetme.c.

References ast_channel::_state, AST_STATE_UP, chan, and CONFFLAG_NO_AUDIO_UNTIL_UP.

Referenced by conf_run().

01596 {
01597    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01598       return 1;
01599    }
01600 
01601    return (chan->_state == AST_STATE_UP);
01602 }

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

Definition at line 664 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

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

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

Definition at line 3522 of file app_meetme.c.

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

Referenced by load_module().

03522                                                                     {
03523    char *params;
03524    struct ast_conference *conf = NULL;
03525    struct ast_conf_user *user = NULL;
03526    AST_DECLARE_APP_ARGS(args,
03527       AST_APP_ARG(channel);
03528       AST_APP_ARG(command);
03529    );
03530 
03531    if (ast_strlen_zero(data)) {
03532       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
03533       return -1;
03534    }
03535    
03536    params = ast_strdupa(data);
03537    AST_STANDARD_APP_ARGS(args, params);
03538 
03539    if (!args.channel) {
03540       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
03541       return -1;
03542    }
03543 
03544    if (!args.command) {
03545       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
03546       return -1;
03547    }
03548 
03549    AST_LIST_LOCK(&confs);
03550    AST_LIST_TRAVERSE(&confs, conf, list) {
03551       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03552          if (!strcmp(user->chan->name, args.channel))
03553             break;
03554       }
03555    }
03556    
03557    if (!user) {
03558       ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
03559       AST_LIST_UNLOCK(&confs);
03560       return 0;
03561    }
03562    
03563    /* perform the specified action */
03564    switch (*args.command) {
03565       case 77: /* M: Mute */ 
03566          user->adminflags |= ADMINFLAG_MUTED;
03567          break;
03568       case 109: /* m: Unmute */ 
03569          user->adminflags &= ~ADMINFLAG_MUTED;
03570          break;
03571       case 107: /* k: Kick user */ 
03572          user->adminflags |= ADMINFLAG_KICKME;
03573          break;
03574       default: /* unknown command */
03575          ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
03576          break;
03577    }
03578 
03579    AST_LIST_UNLOCK(&confs);
03580    
03581    return 0;
03582 }

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

Definition at line 918 of file app_meetme.c.

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

Referenced by meetme_cmd().

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

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

The meetme() application.

Definition at line 3111 of file app_meetme.c.

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

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

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

Definition at line 1320 of file app_meetme.c.

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

Referenced by conf_run().

01321 {
01322    int x;
01323 
01324    /* read any frames that may be waiting on the channel
01325       and throw them away
01326    */
01327    if (chan) {
01328       struct ast_frame *f;
01329 
01330       /* when no frames are available, this will wait
01331          for 1 millisecond maximum
01332       */
01333       while (ast_waitfor(chan, 1)) {
01334          f = ast_read(chan);
01335          if (f)
01336             ast_frfree(f);
01337          else /* channel was hung up or something else happened */
01338             break;
01339       }
01340    }
01341 
01342    /* flush any data sitting in the pseudo channel */
01343    x = DAHDI_FLUSH_ALL;
01344    if (ioctl(fd, DAHDI_FLUSH, &x))
01345       ast_log(LOG_WARNING, "Error flushing channel\n");
01346 
01347 }

static int conf_free ( struct ast_conference conf  )  [static]

Definition at line 1351 of file app_meetme.c.

References ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethread_stop, ao2_ref(), ast_cond_signal(), ast_filedelete(), AST_FRAME_BITS, ast_frfree, AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_translator_free_path(), ast_conference::chan, ast_conference::confno, announce_listitem::entry, EVENT_FLAG_CALL, manager_event, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, announce_listitem::namerecloc, ast_conference::transframe, and ast_conference::transpath.

Referenced by dispose_conf().

01352 {
01353    int x;
01354    struct announce_listitem *item;
01355    
01356    AST_LIST_REMOVE(&confs, conf, list);
01357    manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01358 
01359    if (conf->recording == MEETME_RECORD_ACTIVE) {
01360       conf->recording = MEETME_RECORD_TERMINATE;
01361       AST_LIST_UNLOCK(&confs);
01362       while (1) {
01363          usleep(1);
01364          AST_LIST_LOCK(&confs);
01365          if (conf->recording == MEETME_RECORD_OFF)
01366             break;
01367          AST_LIST_UNLOCK(&confs);
01368       }
01369    }
01370 
01371    for (x = 0; x < AST_FRAME_BITS; x++) {
01372       if (conf->transframe[x])
01373          ast_frfree(conf->transframe[x]);
01374       if (conf->transpath[x])
01375          ast_translator_free_path(conf->transpath[x]);
01376    }
01377    if (conf->announcethread != AST_PTHREADT_NULL) {
01378       ast_mutex_lock(&conf->announcelistlock);
01379       conf->announcethread_stop = 1;
01380       ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01381       ast_cond_signal(&conf->announcelist_addition);
01382       ast_mutex_unlock(&conf->announcelistlock);
01383       pthread_join(conf->announcethread, NULL);
01384    
01385       while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01386          ast_filedelete(item->namerecloc, NULL);
01387          ao2_ref(item, -1);
01388       }
01389       ast_mutex_destroy(&conf->announcelistlock);
01390    }
01391    if (conf->origframe)
01392       ast_frfree(conf->origframe);
01393    if (conf->lchan)
01394       ast_hangup(conf->lchan);
01395    if (conf->chan)
01396       ast_hangup(conf->chan);
01397    if (conf->fd >= 0)
01398       close(conf->fd);
01399 
01400    ast_mutex_destroy(&conf->playlock);
01401    ast_mutex_destroy(&conf->listenlock);
01402    ast_mutex_destroy(&conf->recordthreadlock);
01403    ast_mutex_destroy(&conf->announcethreadlock);
01404    ast_free(conf);
01405 
01406    return 0;
01407 }

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

Definition at line 782 of file app_meetme.c.

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

Referenced by conf_run().

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

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

Definition at line 1409 of file app_meetme.c.

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

Referenced by conf_run().

01411 {
01412    struct ast_conf_user *user;
01413 
01414    AST_LIST_TRAVERSE(&conf->userlist, user, list) {
01415       if (user == sender)
01416          continue;
01417       if (ast_write(user->chan, f) < 0)
01418          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01419    }
01420 }

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

Definition at line 1604 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_conf_user::adminflags, announce_thread(), ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethreadlock, ao2_alloc(), ao2_ref(), app, ast_calloc, ast_channel_setoption(), 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_new(), ast_dsp_silence(), ast_exists_extension(), ast_filedelete(), AST_FORMAT_SLINEAR, ast_frame_adjust_volume(), AST_FRAME_BITS, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_NULL, AST_FRAME_VOICE, ast_free, ast_frfree, AST_FRIENDLY_OFFSET, ast_goto_if_exists(), ast_hangup(), ast_indicate(), AST_LIST_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LAST, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), ast_moh_stop(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_read(), ast_read_noaudio(), ast_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_strdupa, ast_streamfile(), ast_strlen_zero(), ast_translate(), ast_translator_build_path(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_update_realtime(), ast_verb, ast_verbose(), ast_waitfor_nandfds(), ast_waitstream(), ast_write(), ast_channel::audiohooks, buf, can_write(), careful_write(), ast_conf_user::chan, ast_conference::chan, chan, conf_flush(), CONF_HASJOIN, conf_play(), conf_queue_dtmf(), CONF_SIZE, conf_start_moh(), CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_DURATION_LIMIT, CONFFLAG_DURATION_STOP, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_KEYEXIT, CONFFLAG_KICK_CONTINUE, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_SLA_STATION, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, ast_channel::context, ast_conference::dahdiconf, dtmfstr, ast_conference::endalert, ast_conference::endtime, ENTER, announce_listitem::entry, errno, EVENT_FLAG_CALL, exitcontext, f, ast_channel::fds, ast_frame::frame_list, ast_frame::frametype, ast_channel::language, ast_conference::lchan, 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_channel::name, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_EXITKEYS, OPT_ARG_MOH_CLASS, OPT_ARG_WAITMARKED, ast_conference::origframe, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_conference::playlock, ast_channel::rawwriteformat, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, reset_volumes(), s, S_OR, sec, set_talk_volume(), SLA_EVENT_HOLD, sla_queue_event_conf(), strsep(), ast_channel::tech, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_conference::uniqueid, ast_channel::uniqueid, user, ast_conf_user::userflags, ast_conference::userlist, ast_conference::users, var, and VOL_UP.

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

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

Definition at line 1512 of file app_meetme.c.

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

Referenced by conf_run().

01513 {
01514    char *original_moh;
01515 
01516    ast_channel_lock(chan);
01517    original_moh = ast_strdupa(chan->musicclass);
01518    ast_string_field_set(chan, musicclass, musicclass);
01519    ast_channel_unlock(chan);
01520 
01521    ast_moh_start(chan, original_moh, NULL);
01522 
01523    ast_channel_lock(chan);
01524    ast_string_field_set(chan, musicclass, original_moh);
01525    ast_channel_unlock(chan);
01526 }

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

The MeetmeCount application.

Definition at line 3066 of file app_meetme.c.

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

Referenced by load_module().

03067 {
03068    int res = 0;
03069    struct ast_conference *conf;
03070    int count;
03071    char *localdata;
03072    char val[80] = "0"; 
03073    AST_DECLARE_APP_ARGS(args,
03074       AST_APP_ARG(confno);
03075       AST_APP_ARG(varname);
03076    );
03077 
03078    if (ast_strlen_zero(data)) {
03079       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
03080       return -1;
03081    }
03082    
03083    if (!(localdata = ast_strdupa(data)))
03084       return -1;
03085 
03086    AST_STANDARD_APP_ARGS(args, localdata);
03087    
03088    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
03089 
03090    if (conf) {
03091       count = conf->users;
03092       dispose_conf(conf);
03093       conf = NULL;
03094    } else
03095       count = 0;
03096 
03097    if (!ast_strlen_zero(args.varname)) {
03098       /* have var so load it and exit */
03099       snprintf(val, sizeof(val), "%d", count);
03100       pbx_builtin_setvar_helper(chan, args.varname, val);
03101    } else {
03102       if (chan->_state != AST_STATE_UP)
03103          ast_answer(chan);
03104       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
03105    }
03106 
03107    return res;
03108 }

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

Definition at line 5121 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

05122 {
05123    struct sla_trunk_ref *trunk_ref;
05124 
05125    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
05126       return NULL;
05127 
05128    trunk_ref->trunk = trunk;
05129 
05130    return trunk_ref;
05131 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 5332 of file app_meetme.c.

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

Referenced by sla_destroy().

05333 {
05334    struct sla_trunk_ref *trunk_ref;
05335 
05336    if (!ast_strlen_zero(station->autocontext)) {
05337       AST_RWLIST_RDLOCK(&sla_trunks);
05338       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05339          char exten[AST_MAX_EXTENSION];
05340          char hint[AST_MAX_APP];
05341          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05342          snprintf(hint, sizeof(hint), "SLA:%s", exten);
05343          ast_context_remove_extension(station->autocontext, exten, 
05344             1, sla_registrar);
05345          ast_context_remove_extension(station->autocontext, hint, 
05346             PRIORITY_HINT, sla_registrar);
05347       }
05348       AST_RWLIST_UNLOCK(&sla_trunks);
05349    }
05350 
05351    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
05352       ast_free(trunk_ref);
05353 
05354    ast_string_field_free_memory(station);
05355    ast_free(station);
05356 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 5318 of file app_meetme.c.

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

Referenced by sla_destroy().

05319 {
05320    struct sla_station_ref *station_ref;
05321 
05322    if (!ast_strlen_zero(trunk->autocontext))
05323       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
05324 
05325    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
05326       ast_free(station_ref);
05327 
05328    ast_string_field_free_memory(trunk);
05329    ast_free(trunk);
05330 }

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

Definition at line 4833 of file app_meetme.c.

References ast_cond_signal(), ast_dial_answered(), ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_ANSWERED, AST_DIAL_RESULT_FAILED, AST_DIAL_RESULT_HANGUP, AST_DIAL_RESULT_INVALID, AST_DIAL_RESULT_PROCEEDING, AST_DIAL_RESULT_PROGRESS, AST_DIAL_RESULT_RINGING, AST_DIAL_RESULT_TIMEOUT, AST_DIAL_RESULT_TRYING, AST_DIAL_RESULT_UNANSWERED, ast_dial_run(), ast_dial_state(), ast_free, ast_mutex_lock(), ast_mutex_unlock(), ast_strdup, ast_strdupa, ast_strlen_zero(), sla_trunk::chan, sla_trunk_ref::chan, ast_channel::cid, ast_callerid::cid_name, cid_name, ast_callerid::cid_num, cid_num, dial_trunk_args::cond, dial_trunk_args::cond_lock, sla_trunk::device, MAX_CONFNUM, sla, strsep(), sla_trunk_ref::trunk, and dial_trunk_args::trunk_ref.

Referenced by sla_station_exec().

04834 {
04835    struct dial_trunk_args *args = data;
04836    struct ast_dial *dial;
04837    char *tech, *tech_data;
04838    enum ast_dial_result dial_res;
04839    char conf_name[MAX_CONFNUM];
04840    struct ast_conference *conf;
04841    struct ast_flags conf_flags = { 0 };
04842    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
04843    const char *cid_name = NULL, *cid_num = NULL;
04844 
04845    if (!(dial = ast_dial_create())) {
04846       ast_mutex_lock(args->cond_lock);
04847       ast_cond_signal(args->cond);
04848       ast_mutex_unlock(args->cond_lock);
04849       return NULL;
04850    }
04851 
04852    tech_data = ast_strdupa(trunk_ref->trunk->device);
04853    tech = strsep(&tech_data, "/");
04854    if (ast_dial_append(dial, tech, tech_data) == -1) {
04855       ast_mutex_lock(args->cond_lock);
04856       ast_cond_signal(args->cond);
04857       ast_mutex_unlock(args->cond_lock);
04858       ast_dial_destroy(dial);
04859       return NULL;
04860    }
04861 
04862    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
04863       cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
04864       ast_free(trunk_ref->chan->cid.cid_name);
04865       trunk_ref->chan->cid.cid_name = NULL;
04866    }
04867    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
04868       cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
04869       ast_free(trunk_ref->chan->cid.cid_num);
04870       trunk_ref->chan->cid.cid_num = NULL;
04871    }
04872 
04873    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
04874 
04875    if (cid_name)
04876       trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
04877    if (cid_num)
04878       trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
04879 
04880    if (dial_res != AST_DIAL_RESULT_TRYING) {
04881       ast_mutex_lock(args->cond_lock);
04882       ast_cond_signal(args->cond);
04883       ast_mutex_unlock(args->cond_lock);
04884       ast_dial_destroy(dial);
04885       return NULL;
04886    }
04887 
04888    for (;;) {
04889       unsigned int done = 0;
04890       switch ((dial_res = ast_dial_state(dial))) {
04891       case AST_DIAL_RESULT_ANSWERED:
04892          trunk_ref->trunk->chan = ast_dial_answered(dial);
04893       case AST_DIAL_RESULT_HANGUP:
04894       case AST_DIAL_RESULT_INVALID:
04895       case AST_DIAL_RESULT_FAILED:
04896       case AST_DIAL_RESULT_TIMEOUT:
04897       case AST_DIAL_RESULT_UNANSWERED:
04898          done = 1;
04899       case AST_DIAL_RESULT_TRYING:
04900       case AST_DIAL_RESULT_RINGING:
04901       case AST_DIAL_RESULT_PROGRESS:
04902       case AST_DIAL_RESULT_PROCEEDING:
04903          break;
04904       }
04905       if (done)
04906          break;
04907    }
04908 
04909    if (!trunk_ref->trunk->chan) {
04910       ast_mutex_lock(args->cond_lock);
04911       ast_cond_signal(args->cond);
04912       ast_mutex_unlock(args->cond_lock);
04913       ast_dial_join(dial);
04914       ast_dial_destroy(dial);
04915       return NULL;
04916    }
04917 
04918    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04919    ast_set_flag(&conf_flags, 
04920       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
04921       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
04922    conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan);
04923 
04924    ast_mutex_lock(args->cond_lock);
04925    ast_cond_signal(args->cond);
04926    ast_mutex_unlock(args->cond_lock);
04927 
04928    if (conf) {
04929       conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
04930       dispose_conf(conf);
04931       conf = NULL;
04932    }
04933 
04934    /* If the trunk is going away, it is definitely now IDLE. */
04935    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04936 
04937    trunk_ref->trunk->chan = NULL;
04938    trunk_ref->trunk->on_hold = 0;
04939 
04940    ast_dial_join(dial);
04941    ast_dial_destroy(dial);
04942 
04943    return NULL;
04944 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Definition at line 1494 of file app_meetme.c.

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

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

01495 {
01496    int res = 0;
01497    int confno_int = 0;
01498 
01499    AST_LIST_LOCK(&confs);
01500    if (ast_atomic_dec_and_test(&conf->refcount)) {
01501       /* Take the conference room number out of an inuse state */
01502       if ((sscanf(conf->confno, "%d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01503          conf_map[confno_int] = 0;
01504       conf_free(conf);
01505       res = 1;
01506    }
01507    AST_LIST_UNLOCK(&confs);
01508 
01509    return res;
01510 }

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

Definition at line 2968 of file app_meetme.c.

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

Referenced by conf_exec(), and count_exec().

02970 {
02971    struct ast_config *cfg;
02972    struct ast_variable *var;
02973    struct ast_flags config_flags = { 0 };
02974    struct ast_conference *cnf;
02975    char *parse;
02976    AST_DECLARE_APP_ARGS(args,
02977       AST_APP_ARG(confno);
02978       AST_APP_ARG(pin);
02979       AST_APP_ARG(pinadmin);
02980    );
02981 
02982    /* Check first in the conference list */
02983    ast_debug(1, "The requested confno is '%s'?\n", confno);
02984    AST_LIST_LOCK(&confs);
02985    AST_LIST_TRAVERSE(&confs, cnf, list) {
02986       ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
02987       if (!strcmp(confno, cnf->confno)) 
02988          break;
02989    }
02990    if (cnf) {
02991       cnf->refcount += refcount;
02992    }
02993    AST_LIST_UNLOCK(&confs);
02994 
02995    if (!cnf) {
02996       if (dynamic) {
02997          /* No need to parse meetme.conf */
02998          ast_debug(1, "Building dynamic conference '%s'\n", confno);
02999          if (dynamic_pin) {
03000             if (dynamic_pin[0] == 'q') {
03001                /* Query the user to enter a PIN */
03002                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
03003                   return NULL;
03004             }
03005             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
03006          } else {
03007             cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
03008          }
03009       } else {
03010          /* Check the config */
03011          cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03012          if (!cfg) {
03013             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
03014             return NULL;
03015          }
03016          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
03017             if (strcasecmp(var->name, "conf"))
03018                continue;
03019             
03020             if (!(parse = ast_strdupa(var->value)))
03021                return NULL;
03022             
03023             AST_STANDARD_APP_ARGS(args, parse);
03024             ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
03025             if (!strcasecmp(args.confno, confno)) {
03026                /* Bingo it's a valid conference */
03027                cnf = build_conf(args.confno,
03028                      S_OR(args.pin, ""),
03029                      S_OR(args.pinadmin, ""),
03030                      make, dynamic, refcount, chan);
03031                break;
03032             }
03033          }
03034          if (!var) {
03035             ast_debug(1, "%s isn't a valid conference\n", confno);
03036          }
03037          ast_config_destroy(cfg);
03038       }
03039    } else if (dynamic_pin) {
03040       /* Correct for the user selecting 'D' instead of 'd' to have
03041          someone join into a conference that has already been created
03042          with a pin. */
03043       if (dynamic_pin[0] == 'q')
03044          dynamic_pin[0] = '\0';
03045    }
03046 
03047    if (cnf) {
03048       if (confflags && !cnf->chan &&
03049           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03050           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03051          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03052          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03053       }
03054       
03055       if (confflags && !cnf->chan &&
03056           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03057          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03058          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03059       }
03060    }
03061 
03062    return cnf;
03063 }

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

Definition at line 2830 of file app_meetme.c.

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

Referenced by conf_exec().

02833 {
02834    struct ast_variable *var;
02835    struct ast_conference *cnf;
02836 
02837    *too_early = 0;
02838 
02839    /* Check first in the conference list */
02840    AST_LIST_LOCK(&confs);
02841    AST_LIST_TRAVERSE(&confs, cnf, list) {
02842       if (!strcmp(confno, cnf->confno)) 
02843          break;
02844    }
02845    if (cnf) {
02846       cnf->refcount += refcount;
02847    }
02848    AST_LIST_UNLOCK(&confs);
02849 
02850    if (!cnf) {
02851       char *pin = NULL, *pinadmin = NULL; /* For temp use */
02852       int maxusers = 0;
02853       struct timeval now;
02854       char currenttime[19] = "";
02855       char eatime[19] = "";
02856       char useropts[32] = "";
02857       char adminopts[32] = "";
02858       struct ast_tm tm, etm;
02859       struct timeval endtime = { .tv_sec = 0 };
02860 
02861       if (rt_schedule) {
02862          now = ast_tvnow();
02863 
02864          ast_localtime(&now, &tm, NULL);
02865          ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02866 
02867          ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
02868 
02869          var = ast_load_realtime("meetme", "confno",
02870             confno, "starttime <= ", currenttime, "endtime >= ",
02871             currenttime, NULL);
02872 
02873          if (!var && fuzzystart) {
02874             now = ast_tvnow();
02875             now.tv_sec += fuzzystart;
02876 
02877             ast_localtime(&now, &tm, NULL);
02878             ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02879             var = ast_load_realtime("meetme", "confno",
02880                confno, "starttime <= ", currenttime, "endtime >= ",
02881                currenttime, NULL);
02882          }
02883 
02884          if (!var && earlyalert) {
02885             now = ast_tvnow();
02886             now.tv_sec += earlyalert;
02887             ast_localtime(&now, &etm, NULL);
02888             ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
02889             var = ast_load_realtime("meetme", "confno",
02890                confno, "starttime <= ", eatime, "endtime >= ",
02891                currenttime, NULL);
02892             if (var)
02893                *too_early = 1;
02894          }
02895 
02896       } else
02897           var = ast_load_realtime("meetme", "confno", confno, NULL);
02898 
02899       if (!var)
02900          return NULL;
02901 
02902       if (rt_schedule && *too_early) {
02903          /* Announce that the caller is early and exit */
02904          if (!ast_streamfile(chan, "conf-has-not-started", chan->language))
02905             ast_waitstream(chan, "");
02906          ast_variables_destroy(var);
02907          return NULL;
02908       }
02909 
02910       while (var) {
02911          if (!strcasecmp(var->name, "pin")) {
02912             pin = ast_strdupa(var->value);
02913          } else if (!strcasecmp(var->name, "adminpin")) {
02914             pinadmin = ast_strdupa(var->value);
02915          } else if (!strcasecmp(var->name, "opts")) {
02916             ast_copy_string(useropts, var->value, sizeof(useropts));
02917          } else if (!strcasecmp(var->name, "maxusers")) {
02918             maxusers = atoi(var->value);
02919          } else if (!strcasecmp(var->name, "adminopts")) {
02920             ast_copy_string(adminopts, var->value, sizeof(adminopts));
02921          } else if (!strcasecmp(var->name, "endtime")) {
02922             union {
02923                struct ast_tm atm;
02924                struct tm tm;
02925             } t = { { 0, }, };
02926             strptime(var->value, "%Y-%m-%d %H:%M:%S", &t.tm);
02927             /* strptime does not determine if a time is
02928              * in DST or not.  Set tm_isdst to -1 to 
02929              * allow ast_mktime to adjust for DST 
02930              * if needed */
02931             t.tm.tm_isdst = -1; 
02932             endtime = ast_mktime(&t.atm, NULL);
02933          }
02934 
02935          var = var->next;
02936       }
02937 
02938       ast_variables_destroy(var);
02939 
02940       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
02941 
02942       if (cnf) {
02943          cnf->maxusers = maxusers;
02944          cnf->endalert = endalert;
02945          cnf->endtime = endtime.tv_sec;
02946       }
02947    }
02948 
02949    if (cnf) {
02950       if (confflags && !cnf->chan &&
02951           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
02952           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
02953          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
02954          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
02955       }
02956       
02957       if (confflags && !cnf->chan &&
02958           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
02959          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
02960          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
02961       }
02962    }
02963 
02964    return cnf;
02965 }

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

Definition at line 3358 of file app_meetme.c.

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

03359 {
03360    struct ast_conf_user *user = NULL;
03361    int cid;
03362    
03363    sscanf(callerident, "%i", &cid);
03364    if (conf && callerident) {
03365       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03366          if (cid == user->user_no)
03367             return user;
03368       }
03369    }
03370    return NULL;
03371 }

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

Definition at line 1528 of file app_meetme.c.

References CONF_HASJOIN.

Referenced by announce_thread().

01529 {
01530    switch (type) {
01531    case CONF_HASLEFT:
01532       return "conf-hasleft";
01533       break;
01534    case CONF_HASJOIN:
01535       return "conf-hasjoin";
01536       break;
01537    default:
01538       return "";
01539    }
01540 }

static char* istalking ( int  x  )  [static]

Definition at line 654 of file app_meetme.c.

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

static int load_config ( int  reload  )  [static]

Definition at line 5692 of file app_meetme.c.

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

05693 {
05694    load_config_meetme();
05695 
05696    if (reload) {
05697       sla_queue_event(SLA_EVENT_RELOAD);
05698       ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
05699          "and will be completed when the system is idle.\n");
05700       return 0;
05701    }
05702    
05703    return sla_load_config(0);
05704 }

static void load_config_meetme ( void   )  [static]

Definition at line 3817 of file app_meetme.c.

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

Referenced by load_config().

03818 {
03819    struct ast_config *cfg;
03820    struct ast_flags config_flags = { 0 };
03821    const char *val;
03822 
03823    if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags)))
03824       return;
03825 
03826    audio_buffers = DEFAULT_AUDIO_BUFFERS;
03827 
03828    /*  Scheduling support is off by default */
03829    rt_schedule = 0;
03830    fuzzystart = 0;
03831    earlyalert = 0;
03832    endalert = 0;
03833 
03834    /*  Logging of participants defaults to ON for compatibility reasons */
03835    rt_log_members = 1;  
03836 
03837    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03838       if ((sscanf(val, "%d", &audio_buffers) != 1)) {
03839          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03840          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03841       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
03842          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03843             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
03844          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03845       }
03846       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03847          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03848    }
03849 
03850    if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
03851       rt_schedule = ast_true(val);
03852    if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
03853       rt_log_members = ast_true(val);
03854    if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
03855       if ((sscanf(val, "%d", &fuzzystart) != 1)) {
03856          ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
03857          fuzzystart = 0;
03858       } 
03859    }
03860    if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
03861       if ((sscanf(val, "%d", &earlyalert) != 1)) {
03862          ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
03863          earlyalert = 0;
03864       } 
03865    }
03866    if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
03867       if ((sscanf(val, "%d", &endalert) != 1)) {
03868          ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
03869          endalert = 0;
03870       } 
03871    }
03872 
03873    ast_config_destroy(cfg);
03874 }

static int load_module ( void   )  [static]

Definition at line 5729 of file app_meetme.c.

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

05730 {
05731    int res = 0;
05732 
05733    res |= load_config(0);
05734 
05735    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05736    res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 
05737                 action_meetmemute, "Mute a Meetme user");
05738    res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 
05739                 action_meetmeunmute, "Unmute a Meetme user");
05740    res |= ast_manager_register2("MeetmeList", EVENT_FLAG_REPORTING, 
05741                 action_meetmelist, "List participants in a conference", mandescr_meetmelist);
05742    res |= ast_register_application(app4, channel_admin_exec, synopsis4, descrip4);
05743    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
05744    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
05745    res |= ast_register_application(app, conf_exec, synopsis, descrip);
05746    res |= ast_register_application(slastation_app, sla_station_exec,
05747                slastation_synopsis, slastation_desc);
05748    res |= ast_register_application(slatrunk_app, sla_trunk_exec,
05749                slatrunk_synopsis, slatrunk_desc);
05750 
05751    res |= ast_devstate_prov_add("Meetme", meetmestate);
05752    res |= ast_devstate_prov_add("SLA", sla_state);
05753 
05754    return res;
05755 }

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

Definition at line 980 of file app_meetme.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd(), ast_conference::confno, ast_cli_args::fd, ast_conference::isdynamic, ast_cli_args::line, ast_conf_user::list, ast_conference::locked, ast_conference::markedusers, MC_DATA_FORMAT, MC_HEADER_FORMAT, ast_cli_args::n, ast_cli_args::pos, sec, ast_conference::start, total, ast_cli_entry::usage, ast_conference::users, and ast_cli_args::word.

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

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

Definition at line 3584 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strdupa, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), ast_conference::confno, ast_conf_user::list, LOG_NOTICE, s, user, and ast_conference::userlist.

Referenced by action_meetmemute(), and action_meetmeunmute().

03585 {
03586    struct ast_conference *conf;
03587    struct ast_conf_user *user;
03588    const char *confid = astman_get_header(m, "Meetme");
03589    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
03590    int userno;
03591 
03592    if (ast_strlen_zero(confid)) {
03593       astman_send_error(s, m, "Meetme conference not specified");
03594       return 0;
03595    }
03596 
03597    if (ast_strlen_zero(userid)) {
03598       astman_send_error(s, m, "Meetme user number not specified");
03599       return 0;
03600    }
03601 
03602    userno = strtoul(userid, &userid, 10);
03603 
03604    if (*userid) {
03605       astman_send_error(s, m, "Invalid user number");
03606       return 0;
03607    }
03608 
03609    /* Look in the conference list */
03610    AST_LIST_LOCK(&confs);
03611    AST_LIST_TRAVERSE(&confs, conf, list) {
03612       if (!strcmp(confid, conf->confno))
03613          break;
03614    }
03615 
03616    if (!conf) {
03617       AST_LIST_UNLOCK(&confs);
03618       astman_send_error(s, m, "Meetme conference does not exist");
03619       return 0;
03620    }
03621 
03622    AST_LIST_TRAVERSE(&conf->userlist, user, list)
03623       if (user->user_no == userno)
03624          break;
03625 
03626    if (!user) {
03627       AST_LIST_UNLOCK(&confs);
03628       astman_send_error(s, m, "User number not found");
03629       return 0;
03630    }
03631 
03632    if (mute)
03633       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
03634    else
03635       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
03636 
03637    AST_LIST_UNLOCK(&confs);
03638 
03639    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);
03640 
03641    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
03642    return 0;
03643 }

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

Callback for devicestate providers.

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

03796 {
03797    struct ast_conference *conf;
03798 
03799    /* Find conference */
03800    AST_LIST_LOCK(&confs);
03801    AST_LIST_TRAVERSE(&confs, conf, list) {
03802       if (!strcmp(data, conf->confno))
03803          break;
03804    }
03805    AST_LIST_UNLOCK(&confs);
03806    if (!conf)
03807       return AST_DEVICE_INVALID;
03808 
03809 
03810    /* SKREP to fill */
03811    if (!conf->users)
03812       return AST_DEVICE_NOT_INUSE;
03813 
03814    return AST_DEVICE_INUSE;
03815 }

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

Definition at line 5133 of file app_meetme.c.

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

Referenced by sla_trunk_exec().

05134 {
05135    struct sla_ringing_trunk *ringing_trunk;
05136 
05137    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
05138       return NULL;
05139    
05140    ringing_trunk->trunk = trunk;
05141    ringing_trunk->ring_begin = ast_tvnow();
05142 
05143    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
05144 
05145    ast_mutex_lock(&sla.lock);
05146    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
05147    ast_mutex_unlock(&sla.lock);
05148 
05149    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05150 
05151    return ringing_trunk;
05152 }

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

Definition at line 3730 of file app_meetme.c.

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

03731 {
03732    struct ast_conference *cnf = args;
03733    struct ast_frame *f = NULL;
03734    int flags;
03735    struct ast_filestream *s = NULL;
03736    int res = 0;
03737    int x;
03738    const char *oldrecordingfilename = NULL;
03739 
03740    if (!cnf || !cnf->lchan) {
03741       pthread_exit(0);
03742    }
03743 
03744    ast_stopstream(cnf->lchan);
03745    flags = O_CREAT | O_TRUNC | O_WRONLY;
03746 
03747 
03748    cnf->recording = MEETME_RECORD_ACTIVE;
03749    while (ast_waitfor(cnf->lchan, -1) > -1) {
03750       if (cnf->recording == MEETME_RECORD_TERMINATE) {
03751          AST_LIST_LOCK(&confs);
03752          AST_LIST_UNLOCK(&confs);
03753          break;
03754       }
03755       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
03756          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
03757          oldrecordingfilename = cnf->recordingfilename;
03758       }
03759       
03760       f = ast_read(cnf->lchan);
03761       if (!f) {
03762          res = -1;
03763          break;
03764       }
03765       if (f->frametype == AST_FRAME_VOICE) {
03766          ast_mutex_lock(&cnf->listenlock);
03767          for (x = 0; x < AST_FRAME_BITS; x++) {
03768             /* Free any translations that have occured */
03769             if (cnf->transframe[x]) {
03770                ast_frfree(cnf->transframe[x]);
03771                cnf->transframe[x] = NULL;
03772             }
03773          }
03774          if (cnf->origframe)
03775             ast_frfree(cnf->origframe);
03776          cnf->origframe = ast_frdup(f);
03777          ast_mutex_unlock(&cnf->listenlock);
03778          if (s)
03779             res = ast_writestream(s, f);
03780          if (res) {
03781             ast_frfree(f);
03782             break;
03783          }
03784       }
03785       ast_frfree(f);
03786    }
03787    cnf->recording = MEETME_RECORD_OFF;
03788    if (s)
03789       ast_closestream(s);
03790    
03791    pthread_exit(0);
03792 }

static int reload ( void   )  [static]

Definition at line 5757 of file app_meetme.c.

References load_config().

05758 {
05759    return load_config(1);
05760 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 774 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_RXGAIN, AST_OPTION_TXGAIN, and user.

Referenced by admin_exec(), and conf_run().

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

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

Definition at line 4033 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_mutex_lock(), ast_mutex_unlock(), ast_set_flag, 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, MAX_CONFNUM, 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().

04034 {
04035    struct sla_station *station;
04036    struct sla_trunk_ref *trunk_ref;
04037    char conf_name[MAX_CONFNUM];
04038    struct ast_flags conf_flags = { 0 };
04039    struct ast_conference *conf;
04040 
04041    {
04042       struct run_station_args *args = data;
04043       station = args->station;
04044       trunk_ref = args->trunk_ref;
04045       ast_mutex_lock(args->cond_lock);
04046       ast_cond_signal(args->cond);
04047       ast_mutex_unlock(args->cond_lock);
04048       /* args is no longer valid here. */
04049    }
04050 
04051    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
04052    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04053    ast_set_flag(&conf_flags, 
04054       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04055    answer_trunk_chan(trunk_ref->chan);
04056    conf = build_conf(conf_name, "", "", 0, 0, 1, trunk_ref->chan);
04057    if (conf) {
04058       conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
04059       dispose_conf(conf);
04060       conf = NULL;
04061    }
04062    trunk_ref->chan = NULL;
04063    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04064       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04065       strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
04066       admin_exec(NULL, conf_name);
04067       trunk_ref->trunk->hold_stations = 0;
04068       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04069    }
04070 
04071    ast_dial_join(station->dial);
04072    ast_dial_destroy(station->dial);
04073    station->dial = NULL;
04074 
04075    return NULL;
04076 }

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

Definition at line 703 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_TXGAIN, and user.

Referenced by tweak_listen_volume().

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

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

Definition at line 691 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_RXGAIN, and user.

Referenced by conf_run(), and tweak_talk_volume().

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

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

Definition at line 5479 of file app_meetme.c.

References ast_atomic_fetchadd_int(), ast_free, AST_LIST_INSERT_TAIL, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strdupa, create_trunk_ref(), announce_listitem::entry, LOG_WARNING, sla_station::name, sla_trunk::name, sla_trunk::num_stations, sla_trunk_ref::ring_delay, sla_trunk_ref::ring_timeout, sla_create_station_ref(), SLA_TRUNK_STATE_IDLE, sla_trunk_ref::state, sla_station_ref::station, sla_trunk::stations, strsep(), sla_station::trunks, and var.

Referenced by sla_build_station().

05480 {
05481    struct sla_trunk *trunk;
05482    struct sla_trunk_ref *trunk_ref;
05483    struct sla_station_ref *station_ref;
05484    char *trunk_name, *options, *cur;
05485 
05486    options = ast_strdupa(var->value);
05487    trunk_name = strsep(&options, ",");
05488    
05489    AST_RWLIST_RDLOCK(&sla_trunks);
05490    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05491       if (!strcasecmp(trunk->name, trunk_name))
05492          break;
05493    }
05494 
05495    AST_RWLIST_UNLOCK(&sla_trunks);
05496    if (!trunk) {
05497       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
05498       return;
05499    }
05500    if (!(trunk_ref = create_trunk_ref(trunk)))
05501       return;
05502    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
05503 
05504    while ((cur = strsep(&options, ","))) {
05505       char *name, *value = cur;
05506       name = strsep(&value, "=");
05507       if (!strcasecmp(name, "ringtimeout")) {
05508          if (sscanf(value, "%u", &trunk_ref->ring_timeout) != 1) {
05509             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
05510                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05511             trunk_ref->ring_timeout = 0;
05512          }
05513       } else if (!strcasecmp(name, "ringdelay")) {
05514          if (sscanf(value, "%u", &trunk_ref->ring_delay) != 1) {
05515             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
05516                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05517             trunk_ref->ring_delay = 0;
05518          }
05519       } else {
05520          ast_log(LOG_WARNING, "Invalid option '%s' for "
05521             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
05522       }
05523    }
05524 
05525    if (!(station_ref = sla_create_station_ref(station))) {
05526       ast_free(trunk_ref);
05527       return;
05528    }
05529    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
05530    AST_RWLIST_WRLOCK(&sla_trunks);
05531    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
05532    AST_RWLIST_UNLOCK(&sla_trunks);
05533    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
05534 }

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

Definition at line 5536 of file app_meetme.c.

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

Referenced by sla_load_config().

05537 {
05538    struct sla_station *station;
05539    struct ast_variable *var;
05540    const char *dev;
05541 
05542    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05543       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
05544       return -1;
05545    }
05546 
05547    if (!(station = ast_calloc(1, sizeof(*station))))
05548       return -1;
05549    if (ast_string_field_init(station, 32)) {
05550       ast_free(station);
05551       return -1;
05552    }
05553 
05554    ast_string_field_set(station, name, cat);
05555    ast_string_field_set(station, device, dev);
05556 
05557    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05558       if (!strcasecmp(var->name, "trunk"))
05559          sla_add_trunk_to_station(station, var);
05560       else if (!strcasecmp(var->name, "autocontext"))
05561          ast_string_field_set(station, autocontext, var->value);
05562       else if (!strcasecmp(var->name, "ringtimeout")) {
05563          if (sscanf(var->value, "%u", &station->ring_timeout) != 1) {
05564             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
05565                var->value, station->name);
05566             station->ring_timeout = 0;
05567          }
05568       } else if (!strcasecmp(var->name, "ringdelay")) {
05569          if (sscanf(var->value, "%u", &station->ring_delay) != 1) {
05570             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
05571                var->value, station->name);
05572             station->ring_delay = 0;
05573          }
05574       } else if (!strcasecmp(var->name, "hold")) {
05575          if (!strcasecmp(var->value, "private"))
05576             station->hold_access = SLA_HOLD_PRIVATE;
05577          else if (!strcasecmp(var->value, "open"))
05578             station->hold_access = SLA_HOLD_OPEN;
05579          else {
05580             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
05581                var->value, station->name);
05582          }
05583 
05584       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05585          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05586             var->name, var->lineno, SLA_CONFIG_FILE);
05587       }
05588    }
05589 
05590    if (!ast_strlen_zero(station->autocontext)) {
05591       struct ast_context *context;
05592       struct sla_trunk_ref *trunk_ref;
05593       context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
05594       if (!context) {
05595          ast_log(LOG_ERROR, "Failed to automatically find or create "
05596             "context '%s' for SLA!\n", station->autocontext);
05597          destroy_station(station);
05598          return -1;
05599       }
05600       /* The extension for when the handset goes off-hook.
05601        * exten => station1,1,SLAStation(station1) */
05602       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
05603          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
05604          ast_log(LOG_ERROR, "Failed to automatically create extension "
05605             "for trunk '%s'!\n", station->name);
05606          destroy_station(station);
05607          return -1;
05608       }
05609       AST_RWLIST_RDLOCK(&sla_trunks);
05610       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05611          char exten[AST_MAX_EXTENSION];
05612          char hint[AST_MAX_APP];
05613          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05614          snprintf(hint, sizeof(hint), "SLA:%s", exten);
05615          /* Extension for this line button 
05616           * exten => station1_line1,1,SLAStation(station1_line1) */
05617          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
05618             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
05619             ast_log(LOG_ERROR, "Failed to automatically create extension "
05620                "for trunk '%s'!\n", station->name);
05621             destroy_station(station);
05622             return -1;
05623          }
05624          /* Hint for this line button 
05625           * exten => station1_line1,hint,SLA:station1_line1 */
05626          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
05627             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
05628             ast_log(LOG_ERROR, "Failed to automatically create hint "
05629                "for trunk '%s'!\n", station->name);
05630             destroy_station(station);
05631             return -1;
05632          }
05633       }
05634       AST_RWLIST_UNLOCK(&sla_trunks);
05635    }
05636 
05637    AST_RWLIST_WRLOCK(&sla_stations);
05638    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
05639    AST_RWLIST_UNLOCK(&sla_stations);
05640 
05641    return 0;
05642 }

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

Definition at line 5401 of file app_meetme.c.

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

Referenced by sla_load_config().

05402 {
05403    struct sla_trunk *trunk;
05404    struct ast_variable *var;
05405    const char *dev;
05406 
05407    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05408       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
05409       return -1;
05410    }
05411 
05412    if (sla_check_device(dev)) {
05413       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
05414          cat, dev);
05415       return -1;
05416    }
05417 
05418    if (!(trunk = ast_calloc(1, sizeof(*trunk))))
05419       return -1;
05420    if (ast_string_field_init(trunk, 32)) {
05421       ast_free(trunk);
05422       return -1;
05423    }
05424 
05425    ast_string_field_set(trunk, name, cat);
05426    ast_string_field_set(trunk, device, dev);
05427 
05428    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05429       if (!strcasecmp(var->name, "autocontext"))
05430          ast_string_field_set(trunk, autocontext, var->value);
05431       else if (!strcasecmp(var->name, "ringtimeout")) {
05432          if (sscanf(var->value, "%u", &trunk->ring_timeout) != 1) {
05433             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
05434                var->value, trunk->name);
05435             trunk->ring_timeout = 0;
05436          }
05437       } else if (!strcasecmp(var->name, "barge"))
05438          trunk->barge_disabled = ast_false(var->value);
05439       else if (!strcasecmp(var->name, "hold")) {
05440          if (!strcasecmp(var->value, "private"))
05441             trunk->hold_access = SLA_HOLD_PRIVATE;
05442          else if (!strcasecmp(var->value, "open"))
05443             trunk->hold_access = SLA_HOLD_OPEN;
05444          else {
05445             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
05446                var->value, trunk->name);
05447          }
05448       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05449          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05450             var->name, var->lineno, SLA_CONFIG_FILE);
05451       }
05452    }
05453 
05454    if (!ast_strlen_zero(trunk->autocontext)) {
05455       struct ast_context *context;
05456       context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
05457       if (!context) {
05458          ast_log(LOG_ERROR, "Failed to automatically find or create "
05459             "context '%s' for SLA!\n", trunk->autocontext);
05460          destroy_trunk(trunk);
05461          return -1;
05462       }
05463       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
05464          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
05465          ast_log(LOG_ERROR, "Failed to automatically create extension "
05466             "for trunk '%s'!\n", trunk->name);
05467          destroy_trunk(trunk);
05468          return -1;
05469       }
05470    }
05471 
05472    AST_RWLIST_WRLOCK(&sla_trunks);
05473    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
05474    AST_RWLIST_UNLOCK(&sla_trunks);
05475 
05476    return 0;
05477 }

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

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

Referenced by sla_process_timers().

04646 {
04647    struct sla_station *station;
04648    int res = 0;
04649 
04650    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04651       struct sla_ringing_trunk *ringing_trunk;
04652       int time_left;
04653 
04654       /* Ignore stations already ringing */
04655       if (sla_check_ringing_station(station))
04656          continue;
04657 
04658       /* Ignore stations already on a call */
04659       if (sla_check_inuse_station(station))
04660          continue;
04661 
04662       /* Ignore stations that don't have one of their trunks ringing */
04663       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
04664          continue;
04665 
04666       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
04667          continue;
04668 
04669       /* If there is no time left, then the station needs to start ringing.
04670        * Return non-zero so that an event will be queued up an event to 
04671        * make that happen. */
04672       if (time_left <= 0) {
04673          res = 1;
04674          continue;
04675       }
04676 
04677       if (time_left < *timeout)
04678          *timeout = time_left;
04679    }
04680 
04681    return res;
04682 }

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

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

Referenced by sla_process_timers().

04563 {
04564    struct sla_ringing_trunk *ringing_trunk;
04565    struct sla_ringing_station *ringing_station;
04566    int res = 0;
04567 
04568    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04569       unsigned int ring_timeout = 0;
04570       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
04571       struct sla_trunk_ref *trunk_ref;
04572 
04573       /* If there are any ring timeouts specified for a specific trunk
04574        * on the station, then use the highest per-trunk ring timeout.
04575        * Otherwise, use the ring timeout set for the entire station. */
04576       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04577          struct sla_station_ref *station_ref;
04578          int trunk_time_elapsed, trunk_time_left;
04579 
04580          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04581             if (ringing_trunk->trunk == trunk_ref->trunk)
04582                break;
04583          }
04584          if (!ringing_trunk)
04585             continue;
04586 
04587          /* If there is a trunk that is ringing without a timeout, then the
04588           * only timeout that could matter is a global station ring timeout. */
04589          if (!trunk_ref->ring_timeout)
04590             break;
04591 
04592          /* This trunk on this station is ringing and has a timeout.
04593           * However, make sure this trunk isn't still ringing from a
04594           * previous timeout.  If so, don't consider it. */
04595          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
04596             if (station_ref->station == ringing_station->station)
04597                break;
04598          }
04599          if (station_ref)
04600             continue;
04601 
04602          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04603          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
04604          if (trunk_time_left > final_trunk_time_left)
04605             final_trunk_time_left = trunk_time_left;
04606       }
04607 
04608       /* No timeout was found for ringing trunks, and no timeout for the entire station */
04609       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
04610          continue;
04611 
04612       /* Compute how much time is left for a global station timeout */
04613       if (ringing_station->station->ring_timeout) {
04614          ring_timeout = ringing_station->station->ring_timeout;
04615          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
04616          time_left = (ring_timeout * 1000) - time_elapsed;
04617       }
04618 
04619       /* If the time left based on the per-trunk timeouts is smaller than the
04620        * global station ring timeout, use that. */
04621       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
04622          time_left = final_trunk_time_left;
04623 
04624       /* If there is no time left, the station needs to stop ringing */
04625       if (time_left <= 0) {
04626          AST_LIST_REMOVE_CURRENT(entry);
04627          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
04628          res = 1;
04629          continue;
04630       }
04631 
04632       /* There is still some time left for this station to ring, so save that
04633        * timeout if it is the first event scheduled to occur */
04634       if (time_left < *timeout)
04635          *timeout = time_left;
04636    }
04637    AST_LIST_TRAVERSE_SAFE_END;
04638 
04639    return res;
04640 }

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

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

Referenced by sla_process_timers().

04533 {
04534    struct sla_ringing_trunk *ringing_trunk;
04535    int res = 0;
04536 
04537    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04538       int time_left, time_elapsed;
04539       if (!ringing_trunk->trunk->ring_timeout)
04540          continue;
04541       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04542       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
04543       if (time_left <= 0) {
04544          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
04545          AST_LIST_REMOVE_CURRENT(entry);
04546          sla_stop_ringing_trunk(ringing_trunk);
04547          res = 1;
04548          continue;
04549       }
04550       if (time_left < *timeout)
04551          *timeout = time_left;
04552    }
04553    AST_LIST_TRAVERSE_SAFE_END;
04554 
04555    return res;
04556 }

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

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

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

04003 {
04004    struct sla_station *station;
04005    struct sla_trunk_ref *trunk_ref;
04006 
04007    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04008       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04009          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
04010             || trunk_ref == exclude)
04011             continue;
04012          trunk_ref->state = state;
04013          ast_devstate_changed(sla_state_to_devstate(state), 
04014             "SLA:%s_%s", station->name, trunk->name);
04015          break;
04016       }
04017    }
04018 }

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

Definition at line 5388 of file app_meetme.c.

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

Referenced by sla_build_trunk().

05389 {
05390    char *tech, *tech_data;
05391 
05392    tech_data = ast_strdupa(device);
05393    tech = strsep(&tech_data, "/");
05394 
05395    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
05396       return -1;
05397 
05398    return 0;
05399 }

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

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

Referenced by sla_ring_stations().

04281 {
04282    struct sla_failed_station *failed_station;
04283    int res = 0;
04284 
04285    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
04286       if (station != failed_station->station)
04287          continue;
04288       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
04289          AST_LIST_REMOVE_CURRENT(entry);
04290          ast_free(failed_station);
04291          break;
04292       }
04293       res = 1;
04294    }
04295    AST_LIST_TRAVERSE_SAFE_END
04296 
04297    return res;
04298 }

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

Check to see if a station is in use.

Definition at line 4366 of file app_meetme.c.

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

Referenced by sla_calc_station_delays(), and sla_ring_stations().

04367 {
04368    struct sla_trunk_ref *trunk_ref;
04369 
04370    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04371       if (trunk_ref->chan)
04372          return 1;
04373    }
04374 
04375    return 0;
04376 }

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

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

Referenced by sla_thread().

04725 {
04726    struct sla_station *station;
04727    struct sla_trunk *trunk;
04728 
04729    ast_mutex_lock(&sla.lock);
04730 
04731    if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
04732       || !AST_LIST_EMPTY(&sla.ringing_stations)) {
04733       ast_mutex_unlock(&sla.lock);
04734       return;
04735    }
04736 
04737    AST_RWLIST_RDLOCK(&sla_stations);
04738    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
04739       if (station->ref_count)
04740          break;
04741    }
04742    AST_RWLIST_UNLOCK(&sla_stations);
04743    if (station) {
04744       ast_mutex_unlock(&sla.lock);
04745       return;
04746    }
04747 
04748    AST_RWLIST_RDLOCK(&sla_trunks);
04749    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04750       if (trunk->ref_count)
04751          break;
04752    }
04753    AST_RWLIST_UNLOCK(&sla_trunks);
04754    if (trunk) {
04755       ast_mutex_unlock(&sla.lock);
04756       return;
04757    }
04758 
04759    /* yay */
04760    sla_load_config(1);
04761    sla.reload = 0;
04762 
04763    ast_mutex_unlock(&sla.lock);
04764 }

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

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

Referenced by sla_calc_station_delays(), and sla_ring_stations().

04266 {
04267    struct sla_ringing_station *ringing_station;
04268 
04269    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
04270       if (station == ringing_station->station)
04271          return 1;
04272    }
04273 
04274    return 0;
04275 }

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

04398 {
04399    struct sla_trunk_ref *trunk_ref;
04400    unsigned int delay = UINT_MAX;
04401    int time_left, time_elapsed;
04402 
04403    if (!ringing_trunk)
04404       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
04405    else
04406       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
04407 
04408    if (!ringing_trunk || !trunk_ref)
04409       return delay;
04410 
04411    /* If this station has a ring delay specific to the highest priority
04412     * ringing trunk, use that.  Otherwise, use the ring delay specified
04413     * globally for the station. */
04414    delay = trunk_ref->ring_delay;
04415    if (!delay)
04416       delay = station->ring_delay;
04417    if (!delay)
04418       return INT_MAX;
04419 
04420    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04421    time_left = (delay * 1000) - time_elapsed;
04422 
04423    return time_left;
04424 }

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

Definition at line 3906 of file app_meetme.c.

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

Referenced by sla_find_trunk_ref_byname().

03908 {
03909    struct sla_station_ref *station_ref;
03910    struct sla_trunk_ref *trunk_ref;
03911 
03912    /* For each station that has this call on hold, check for private hold. */
03913    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03914       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03915          if (trunk_ref->trunk != trunk || station_ref->station == station)
03916             continue;
03917          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03918             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03919             return 1;
03920          return 0;
03921       }
03922    }
03923 
03924    return 0;
03925 }

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

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

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

04138 {
04139    struct sla_station_ref *timed_out_station;
04140 
04141    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
04142       if (station == timed_out_station->station)
04143          return 1;
04144    }
04145 
04146    return 0;
04147 }

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

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

Definition at line 4948 of file app_meetme.c.

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

Referenced by sla_station_exec().

04949 {
04950    struct sla_trunk_ref *trunk_ref = NULL;
04951 
04952    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04953       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
04954          break;
04955    }
04956 
04957    return trunk_ref;
04958 }

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

Choose the highest priority ringing trunk for a station.

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

Definition at line 4157 of file app_meetme.c.

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

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

04159 {
04160    struct sla_trunk_ref *s_trunk_ref;
04161    struct sla_ringing_trunk *ringing_trunk = NULL;
04162 
04163    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
04164       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04165          /* Make sure this is the trunk we're looking for */
04166          if (s_trunk_ref->trunk != ringing_trunk->trunk)
04167             continue;
04168 
04169          /* This trunk on the station is ringing.  But, make sure this station
04170           * didn't already time out while this trunk was ringing. */
04171          if (sla_check_timed_out_station(ringing_trunk, station))
04172             continue;
04173 
04174          if (remove)
04175             AST_LIST_REMOVE_CURRENT(entry);
04176 
04177          if (trunk_ref)
04178             *trunk_ref = s_trunk_ref;
04179 
04180          break;
04181       }
04182       AST_LIST_TRAVERSE_SAFE_END;
04183    
04184       if (ringing_trunk)
04185          break;
04186    }
04187 
04188    return ringing_trunk;
04189 }

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

Definition at line 3971 of file app_meetme.c.

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

Referenced by sla_ring_station().

03972 {
03973    struct sla_ringing_station *ringing_station;
03974 
03975    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
03976       return NULL;
03977 
03978    ringing_station->station = station;
03979    ringing_station->ring_begin = ast_tvnow();
03980 
03981    return ringing_station;
03982 }

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

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

03960 {
03961    struct sla_station_ref *station_ref;
03962 
03963    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
03964       return NULL;
03965 
03966    station_ref->station = station;
03967 
03968    return station_ref;
03969 }

static void sla_destroy ( void   )  [static]

Definition at line 5358 of file app_meetme.c.

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

Referenced by unload_module().

05359 {
05360    struct sla_trunk *trunk;
05361    struct sla_station *station;
05362 
05363    AST_RWLIST_WRLOCK(&sla_trunks);
05364    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
05365       destroy_trunk(trunk);
05366    AST_RWLIST_UNLOCK(&sla_trunks);
05367 
05368    AST_RWLIST_WRLOCK(&sla_stations);
05369    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
05370       destroy_station(station);
05371    AST_RWLIST_UNLOCK(&sla_stations);
05372 
05373    if (sla.thread != AST_PTHREADT_NULL) {
05374       ast_mutex_lock(&sla.lock);
05375       sla.stop = 1;
05376       ast_cond_signal(&sla.cond);
05377       ast_mutex_unlock(&sla.lock);
05378       pthread_join(sla.thread, NULL);
05379    }
05380 
05381    /* Drop any created contexts from the dialplan */
05382    ast_context_destroy(NULL, sla_registrar);
05383 
05384    ast_mutex_destroy(&sla.lock);
05385    ast_cond_destroy(&sla.cond);
05386 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 4128 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

04129 {
04130    sla_queue_event(SLA_EVENT_DIAL_STATE);
04131 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 3894 of file app_meetme.c.

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

Referenced by sla_station_exec().

03895 {
03896    struct sla_station *station = NULL;
03897 
03898    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03899       if (!strcasecmp(station->name, name))
03900          break;
03901    }
03902 
03903    return station;
03904 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 3879 of file app_meetme.c.

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

Referenced by sla_trunk_exec().

03880 {
03881    struct sla_trunk *trunk = NULL;
03882 
03883    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03884       if (!strcasecmp(trunk->name, name))
03885          break;
03886    }
03887 
03888    return trunk;
03889 }

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

Definition at line 4378 of file app_meetme.c.

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

Referenced by sla_check_station_delay().

04380 {
04381    struct sla_trunk_ref *trunk_ref = NULL;
04382 
04383    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04384       if (trunk_ref->trunk == trunk)
04385          break;
04386    }
04387 
04388    return trunk_ref;
04389 }

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

Find a trunk reference on a station by name.

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

Definition at line 3934 of file app_meetme.c.

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

Referenced by sla_station_exec().

03936 {
03937    struct sla_trunk_ref *trunk_ref = NULL;
03938 
03939    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03940       if (strcasecmp(trunk_ref->trunk->name, name))
03941          continue;
03942 
03943       if ( (trunk_ref->trunk->barge_disabled 
03944          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
03945          (trunk_ref->trunk->hold_stations 
03946          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
03947          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
03948          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
03949       {
03950          trunk_ref = NULL;
03951       }
03952 
03953       break;
03954    }
03955 
03956    return trunk_ref;
03957 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 4191 of file app_meetme.c.

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

Referenced by sla_thread().

04192 {
04193    struct sla_ringing_station *ringing_station;
04194 
04195    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04196       struct sla_trunk_ref *s_trunk_ref = NULL;
04197       struct sla_ringing_trunk *ringing_trunk = NULL;
04198       struct run_station_args args;
04199       enum ast_dial_result dial_res;
04200       pthread_t dont_care;
04201       ast_mutex_t cond_lock;
04202       ast_cond_t cond;
04203 
04204       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
04205       case AST_DIAL_RESULT_HANGUP:
04206       case AST_DIAL_RESULT_INVALID:
04207       case AST_DIAL_RESULT_FAILED:
04208       case AST_DIAL_RESULT_TIMEOUT:
04209       case AST_DIAL_RESULT_UNANSWERED:
04210          AST_LIST_REMOVE_CURRENT(entry);
04211          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
04212          break;
04213       case AST_DIAL_RESULT_ANSWERED:
04214          AST_LIST_REMOVE_CURRENT(entry);
04215          /* Find the appropriate trunk to answer. */
04216          ast_mutex_lock(&sla.lock);
04217          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
04218          ast_mutex_unlock(&sla.lock);
04219          if (!ringing_trunk) {
04220             ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
04221             break;
04222          }
04223          /* Track the channel that answered this trunk */
04224          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
04225          /* Actually answer the trunk */
04226          answer_trunk_chan(ringing_trunk->trunk->chan);
04227          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04228          /* Now, start a thread that will connect this station to the trunk.  The rest of
04229           * the code here sets up the thread and ensures that it is able to save the arguments
04230           * before they are no longer valid since they are allocated on the stack. */
04231          args.trunk_ref = s_trunk_ref;
04232          args.station = ringing_station->station;
04233          args.cond = &cond;
04234          args.cond_lock = &cond_lock;
04235          ast_free(ringing_trunk);
04236          ast_free(ringing_station);
04237          ast_mutex_init(&cond_lock);
04238          ast_cond_init(&cond, NULL);
04239          ast_mutex_lock(&cond_lock);
04240          ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
04241          ast_cond_wait(&cond, &cond_lock);
04242          ast_mutex_unlock(&cond_lock);
04243          ast_mutex_destroy(&cond_lock);
04244          ast_cond_destroy(&cond);
04245          break;
04246       case AST_DIAL_RESULT_TRYING:
04247       case AST_DIAL_RESULT_RINGING:
04248       case AST_DIAL_RESULT_PROGRESS:
04249       case AST_DIAL_RESULT_PROCEEDING:
04250          break;
04251       }
04252       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
04253          /* Queue up reprocessing ringing trunks, and then ringing stations again */
04254          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04255          sla_queue_event(SLA_EVENT_DIAL_STATE);
04256          break;
04257       }
04258    }
04259    AST_LIST_TRAVERSE_SAFE_END;
04260 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 4508 of file app_meetme.c.

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

Referenced by sla_thread().

04509 {
04510    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
04511    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
04512    ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
04513       event->station->name, event->trunk_ref->trunk->name);
04514    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
04515       INACTIVE_TRUNK_REFS, event->trunk_ref);
04516 
04517    if (event->trunk_ref->trunk->active_stations == 1) {
04518       /* The station putting it on hold is the only one on the call, so start
04519        * Music on hold to the trunk. */
04520       event->trunk_ref->trunk->on_hold = 1;
04521       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
04522    }
04523 
04524    ast_softhangup(event->trunk_ref->chan, AST_CAUSE_NORMAL);
04525    event->trunk_ref->chan = NULL;
04526 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 4498 of file app_meetme.c.

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

Referenced by sla_thread().

04499 {
04500    ast_mutex_lock(&sla.lock);
04501    sla_ring_stations();
04502    ast_mutex_unlock(&sla.lock);
04503 
04504    /* Find stations that shouldn't be ringing anymore. */
04505    sla_hangup_stations();
04506 }

static void sla_hangup_stations ( void   )  [static]

Definition at line 4470 of file app_meetme.c.

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

Referenced by sla_handle_ringing_trunk_event().

04471 {
04472    struct sla_trunk_ref *trunk_ref;
04473    struct sla_ringing_station *ringing_station;
04474 
04475    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04476       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04477          struct sla_ringing_trunk *ringing_trunk;
04478          ast_mutex_lock(&sla.lock);
04479          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04480             if (trunk_ref->trunk == ringing_trunk->trunk)
04481                break;
04482          }
04483          ast_mutex_unlock(&sla.lock);
04484          if (ringing_trunk)
04485             break;
04486       }
04487       if (!trunk_ref) {
04488          AST_LIST_REMOVE_CURRENT(entry);
04489          ast_dial_join(ringing_station->station->dial);
04490          ast_dial_destroy(ringing_station->station->dial);
04491          ringing_station->station->dial = NULL;
04492          ast_free(ringing_station);
04493       }
04494    }
04495    AST_LIST_TRAVERSE_SAFE_END
04496 }

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

Definition at line 1156 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01157 {
01158    const char *hold = "Unknown";
01159 
01160    switch (hold_access) {
01161    case SLA_HOLD_OPEN:
01162       hold = "Open";
01163       break;
01164    case SLA_HOLD_PRIVATE:
01165       hold = "Private";
01166    default:
01167       break;
01168    }
01169 
01170    return hold;
01171 }

static int sla_load_config ( int  reload  )  [static]

Definition at line 5644 of file app_meetme.c.

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

Referenced by load_config(), and sla_check_reload().

05645 {
05646    struct ast_config *cfg;
05647    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
05648    const char *cat = NULL;
05649    int res = 0;
05650    const char *val;
05651 
05652    if (!reload) {
05653       ast_mutex_init(&sla.lock);
05654       ast_cond_init(&sla.cond, NULL);
05655    }
05656 
05657    if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags)))
05658       return 0; /* Treat no config as normal */
05659    else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
05660       return 0;
05661 
05662    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
05663       sla.attempt_callerid = ast_true(val);
05664 
05665    while ((cat = ast_category_browse(cfg, cat)) && !res) {
05666       const char *type;
05667       if (!strcasecmp(cat, "general"))
05668          continue;
05669       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
05670          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
05671             SLA_CONFIG_FILE);
05672          continue;
05673       }
05674       if (!strcasecmp(type, "trunk"))
05675          res = sla_build_trunk(cfg, cat);
05676       else if (!strcasecmp(type, "station"))
05677          res = sla_build_station(cfg, cat);
05678       else {
05679          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
05680             SLA_CONFIG_FILE, type);
05681       }
05682    }
05683 
05684    ast_config_destroy(cfg);
05685 
05686    if (!reload && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations)))
05687       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
05688 
05689    return res;
05690 }

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

04687 {
04688    unsigned int timeout = UINT_MAX;
04689    struct timeval tv;
04690    unsigned int change_made = 0;
04691 
04692    /* Check for ring timeouts on ringing trunks */
04693    if (sla_calc_trunk_timeouts(&timeout))
04694       change_made = 1;
04695 
04696    /* Check for ring timeouts on ringing stations */
04697    if (sla_calc_station_timeouts(&timeout))
04698       change_made = 1;
04699 
04700    /* Check for station ring delays */
04701    if (sla_calc_station_delays(&timeout))
04702       change_made = 1;
04703 
04704    /* queue reprocessing of ringing trunks */
04705    if (change_made)
04706       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
04707 
04708    /* No timeout */
04709    if (timeout == UINT_MAX)
04710       return 0;
04711 
04712    if (ts) {
04713       tv = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
04714       ts->tv_sec = tv.tv_sec;
04715       ts->tv_nsec = tv.tv_usec * 1000;
04716    }
04717 
04718    return 1;
04719 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

Definition at line 1454 of file app_meetme.c.

References sla_queue_event_full().

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

01455 {
01456    sla_queue_event_full(type, NULL, NULL, 1);
01457 }

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

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

Referenced by conf_run().

01462 {
01463    struct sla_station *station;
01464    struct sla_trunk_ref *trunk_ref = NULL;
01465    char *trunk_name;
01466 
01467    trunk_name = ast_strdupa(conf->confno);
01468    strsep(&trunk_name, "_");
01469    if (ast_strlen_zero(trunk_name)) {
01470       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01471       return;
01472    }
01473 
01474    AST_RWLIST_RDLOCK(&sla_stations);
01475    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01476       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01477          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01478             break;
01479       }
01480       if (trunk_ref)
01481          break;
01482    }
01483    AST_RWLIST_UNLOCK(&sla_stations);
01484 
01485    if (!trunk_ref) {
01486       ast_debug(1, "Trunk not found for event!\n");
01487       return;
01488    }
01489 
01490    sla_queue_event_full(type, trunk_ref, station, 1);
01491 }

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

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

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

01424 {
01425    struct sla_event *event;
01426 
01427    if (sla.thread == AST_PTHREADT_NULL) {
01428       return;
01429    }
01430 
01431    if (!(event = ast_calloc(1, sizeof(*event))))
01432       return;
01433 
01434    event->type = type;
01435    event->trunk_ref = trunk_ref;
01436    event->station = station;
01437 
01438    if (!lock) {
01439       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01440       return;
01441    }
01442 
01443    ast_mutex_lock(&sla.lock);
01444    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01445    ast_cond_signal(&sla.cond);
01446    ast_mutex_unlock(&sla.lock);
01447 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1449 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01450 {
01451    sla_queue_event_full(type, NULL, NULL, 0);
01452 }

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

References ast_calloc, ast_dial_append(), ast_dial_create(), ast_dial_destroy(), ast_dial_join(), AST_DIAL_RESULT_TRYING, ast_dial_run(), ast_dial_set_state_callback(), ast_free, AST_LIST_INSERT_HEAD, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_tvnow(), sla_trunk::chan, ast_channel::cid, ast_callerid::cid_name, cid_name, ast_callerid::cid_num, cid_num, sla_station::device, sla_station::dial, announce_listitem::entry, sla, sla_create_ringing_station(), sla_dial_state_callback(), sla_failed_station::station, sla_ringing_station::station, strsep(), and sla_ringing_trunk::trunk.

Referenced by sla_ring_stations().

04304 {
04305    char *tech, *tech_data;
04306    struct ast_dial *dial;
04307    struct sla_ringing_station *ringing_station;
04308    const char *cid_name = NULL, *cid_num = NULL;
04309    enum ast_dial_result res;
04310 
04311    if (!(dial = ast_dial_create()))
04312       return -1;
04313 
04314    ast_dial_set_state_callback(dial, sla_dial_state_callback);
04315    tech_data = ast_strdupa(station->device);
04316    tech = strsep(&tech_data, "/");
04317 
04318    if (ast_dial_append(dial, tech, tech_data) == -1) {
04319       ast_dial_destroy(dial);
04320       return -1;
04321    }
04322 
04323    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
04324       cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
04325       ast_free(ringing_trunk->trunk->chan->cid.cid_name);
04326       ringing_trunk->trunk->chan->cid.cid_name = NULL;
04327    }
04328    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
04329       cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
04330       ast_free(ringing_trunk->trunk->chan->cid.cid_num);
04331       ringing_trunk->trunk->chan->cid.cid_num = NULL;
04332    }
04333 
04334    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
04335    
04336    if (cid_name)
04337       ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
04338    if (cid_num)
04339       ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
04340    
04341    if (res != AST_DIAL_RESULT_TRYING) {
04342       struct sla_failed_station *failed_station;
04343       ast_dial_destroy(dial);
04344       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
04345          return -1;
04346       failed_station->station = station;
04347       failed_station->last_try = ast_tvnow();
04348       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
04349       return -1;
04350    }
04351    if (!(ringing_station = sla_create_ringing_station(station))) {
04352       ast_dial_join(dial);
04353       ast_dial_destroy(dial);
04354       return -1;
04355    }
04356 
04357    station->dial = dial;
04358 
04359    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
04360 
04361    return 0;
04362 }

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

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

Referenced by sla_handle_ringing_trunk_event().

04430 {
04431    struct sla_station_ref *station_ref;
04432    struct sla_ringing_trunk *ringing_trunk;
04433 
04434    /* Make sure that every station that uses at least one of the ringing
04435     * trunks, is ringing. */
04436    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04437       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
04438          int time_left;
04439 
04440          /* Is this station already ringing? */
04441          if (sla_check_ringing_station(station_ref->station))
04442             continue;
04443 
04444          /* Is this station already in a call? */
04445          if (sla_check_inuse_station(station_ref->station))
04446             continue;
04447 
04448          /* Did we fail to dial this station earlier?  If so, has it been
04449           * a minute since we tried? */
04450          if (sla_check_failed_station(station_ref->station))
04451             continue;
04452 
04453          /* If this station already timed out while this trunk was ringing,
04454           * do not dial it again for this ringing trunk. */
04455          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
04456             continue;
04457 
04458          /* Check for a ring delay in progress */
04459          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
04460          if (time_left != INT_MAX && time_left > 0)
04461             continue;
04462 
04463          /* It is time to make this station begin to ring.  Do it! */
04464          sla_ring_station(ringing_trunk, station_ref->station);
04465       }
04466    }
04467    /* Now, all of the stations that should be ringing, are ringing. */
04468 }

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

Definition at line 1238 of file app_meetme.c.

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

01239 {
01240    const struct sla_station *station;
01241 
01242    switch (cmd) {
01243    case CLI_INIT:
01244       e->command = "sla show stations";
01245       e->usage =
01246          "Usage: sla show stations\n"
01247          "       This will list all stations defined in sla.conf\n";
01248       return NULL;
01249    case CLI_GENERATE:
01250       return NULL;
01251    }
01252 
01253    ast_cli(a->fd, "\n" 
01254                "=============================================================\n"
01255                "=== Configured SLA Stations =================================\n"
01256                "=============================================================\n"
01257                "===\n");
01258    AST_RWLIST_RDLOCK(&sla_stations);
01259    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01260       struct sla_trunk_ref *trunk_ref;
01261       char ring_timeout[16] = "(none)";
01262       char ring_delay[16] = "(none)";
01263       if (station->ring_timeout) {
01264          snprintf(ring_timeout, sizeof(ring_timeout), 
01265             "%u", station->ring_timeout);
01266       }
01267       if (station->ring_delay) {
01268          snprintf(ring_delay, sizeof(ring_delay), 
01269             "%u", station->ring_delay);
01270       }
01271       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01272                   "=== Station Name:    %s\n"
01273                   "=== ==> Device:      %s\n"
01274                   "=== ==> AutoContext: %s\n"
01275                   "=== ==> RingTimeout: %s\n"
01276                   "=== ==> RingDelay:   %s\n"
01277                   "=== ==> HoldAccess:  %s\n"
01278                   "=== ==> Trunks ...\n",
01279                   station->name, station->device,
01280                   S_OR(station->autocontext, "(none)"), 
01281                   ring_timeout, ring_delay,
01282                   sla_hold_str(station->hold_access));
01283       AST_RWLIST_RDLOCK(&sla_trunks);
01284       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01285          if (trunk_ref->ring_timeout) {
01286             snprintf(ring_timeout, sizeof(ring_timeout),
01287                "%u", trunk_ref->ring_timeout);
01288          } else
01289             strcpy(ring_timeout, "(none)");
01290          if (trunk_ref->ring_delay) {
01291             snprintf(ring_delay, sizeof(ring_delay),
01292                "%u", trunk_ref->ring_delay);
01293          } else
01294             strcpy(ring_delay, "(none)");
01295             ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
01296                      "===       ==> State:       %s\n"
01297                      "===       ==> RingTimeout: %s\n"
01298                      "===       ==> RingDelay:   %s\n",
01299                      trunk_ref->trunk->name,
01300                      trunkstate2str(trunk_ref->state),
01301                      ring_timeout, ring_delay);
01302       }
01303       AST_RWLIST_UNLOCK(&sla_trunks);
01304       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01305                   "===\n");
01306    }
01307    AST_RWLIST_UNLOCK(&sla_stations);
01308    ast_cli(a->fd, "============================================================\n"
01309                "\n");
01310 
01311    return CLI_SUCCESS;
01312 }

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

Definition at line 1173 of file app_meetme.c.

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

01174 {
01175    const struct sla_trunk *trunk;
01176 
01177    switch (cmd) {
01178    case CLI_INIT:
01179       e->command = "sla show trunks";
01180       e->usage =
01181          "Usage: sla show trunks\n"
01182          "       This will list all trunks defined in sla.conf\n";
01183       return NULL;
01184    case CLI_GENERATE:
01185       return NULL;
01186    }
01187 
01188    ast_cli(a->fd, "\n"
01189                "=============================================================\n"
01190                "=== Configured SLA Trunks ===================================\n"
01191                "=============================================================\n"
01192                "===\n");
01193    AST_RWLIST_RDLOCK(&sla_trunks);
01194    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01195       struct sla_station_ref *station_ref;
01196       char ring_timeout[16] = "(none)";
01197       if (trunk->ring_timeout)
01198          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01199       ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01200                   "=== Trunk Name:       %s\n"
01201                   "=== ==> Device:       %s\n"
01202                   "=== ==> AutoContext:  %s\n"
01203                   "=== ==> RingTimeout:  %s\n"
01204                   "=== ==> BargeAllowed: %s\n"
01205                   "=== ==> HoldAccess:   %s\n"
01206                   "=== ==> Stations ...\n",
01207                   trunk->name, trunk->device, 
01208                   S_OR(trunk->autocontext, "(none)"), 
01209                   ring_timeout,
01210                   trunk->barge_disabled ? "No" : "Yes",
01211                   sla_hold_str(trunk->hold_access));
01212       AST_RWLIST_RDLOCK(&sla_stations);
01213       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01214          ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
01215       AST_RWLIST_UNLOCK(&sla_stations);
01216       ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
01217    }
01218    AST_RWLIST_UNLOCK(&sla_trunks);
01219    ast_cli(a->fd, "=============================================================\n\n");
01220 
01221    return CLI_SUCCESS;
01222 }

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

Definition at line 5282 of file app_meetme.c.

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

Referenced by load_module().

05283 {
05284    char *buf, *station_name, *trunk_name;
05285    struct sla_station *station;
05286    struct sla_trunk_ref *trunk_ref;
05287    enum ast_device_state res = AST_DEVICE_INVALID;
05288 
05289    trunk_name = buf = ast_strdupa(data);
05290    station_name = strsep(&trunk_name, "_");
05291 
05292    AST_RWLIST_RDLOCK(&sla_stations);
05293    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05294       if (strcasecmp(station_name, station->name))
05295          continue;
05296       AST_RWLIST_RDLOCK(&sla_trunks);
05297       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05298          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
05299             break;
05300       }
05301       if (!trunk_ref) {
05302          AST_RWLIST_UNLOCK(&sla_trunks);
05303          break;
05304       }
05305       res = sla_state_to_devstate(trunk_ref->state);
05306       AST_RWLIST_UNLOCK(&sla_trunks);
05307    }
05308    AST_RWLIST_UNLOCK(&sla_stations);
05309 
05310    if (res == AST_DEVICE_INVALID) {
05311       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
05312          trunk_name, station_name);
05313    }
05314 
05315    return res;
05316 }

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

Definition at line 3984 of file app_meetme.c.

References AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_DEVICE_UNKNOWN, SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, and SLA_TRUNK_STATE_UP.

Referenced by sla_change_trunk_state(), and sla_state().

03985 {
03986    switch (state) {
03987    case SLA_TRUNK_STATE_IDLE:
03988       return AST_DEVICE_NOT_INUSE;
03989    case SLA_TRUNK_STATE_RINGING:
03990       return AST_DEVICE_RINGING;
03991    case SLA_TRUNK_STATE_UP:
03992       return AST_DEVICE_INUSE;
03993    case SLA_TRUNK_STATE_ONHOLD:
03994    case SLA_TRUNK_STATE_ONHOLD_BYME:
03995       return AST_DEVICE_ONHOLD;
03996    }
03997 
03998    return AST_DEVICE_UNKNOWN;
03999 }

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

Definition at line 4960 of file app_meetme.c.

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

Referenced by load_module().

04961 {
04962    char *station_name, *trunk_name;
04963    struct sla_station *station;
04964    struct sla_trunk_ref *trunk_ref = NULL;
04965    char conf_name[MAX_CONFNUM];
04966    struct ast_flags conf_flags = { 0 };
04967    struct ast_conference *conf;
04968 
04969    if (ast_strlen_zero(data)) {
04970       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04971       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04972       return 0;
04973    }
04974 
04975    trunk_name = ast_strdupa(data);
04976    station_name = strsep(&trunk_name, "_");
04977 
04978    if (ast_strlen_zero(station_name)) {
04979       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04980       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04981       return 0;
04982    }
04983 
04984    AST_RWLIST_RDLOCK(&sla_stations);
04985    station = sla_find_station(station_name);
04986    if (station)
04987       ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
04988    AST_RWLIST_UNLOCK(&sla_stations);
04989 
04990    if (!station) {
04991       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
04992       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04993       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
04994       return 0;
04995    }
04996 
04997    AST_RWLIST_RDLOCK(&sla_trunks);
04998    if (!ast_strlen_zero(trunk_name)) {
04999       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
05000    } else
05001       trunk_ref = sla_choose_idle_trunk(station);
05002    AST_RWLIST_UNLOCK(&sla_trunks);
05003 
05004    if (!trunk_ref) {
05005       if (ast_strlen_zero(trunk_name))
05006          ast_log(LOG_NOTICE, "No trunks available for call.\n");
05007       else {
05008          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
05009             "'%s' due to access controls.\n", trunk_name);
05010       }
05011       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05012       ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05013       sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05014       return 0;
05015    }
05016 
05017    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
05018       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
05019          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05020       else {
05021          trunk_ref->state = SLA_TRUNK_STATE_UP;
05022          ast_devstate_changed(AST_DEVICE_INUSE, 
05023             "SLA:%s_%s", station->name, trunk_ref->trunk->name);
05024       }
05025    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
05026       struct sla_ringing_trunk *ringing_trunk;
05027 
05028       ast_mutex_lock(&sla.lock);
05029       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05030          if (ringing_trunk->trunk == trunk_ref->trunk) {
05031             AST_LIST_REMOVE_CURRENT(entry);
05032             break;
05033          }
05034       }
05035       AST_LIST_TRAVERSE_SAFE_END
05036       ast_mutex_unlock(&sla.lock);
05037 
05038       if (ringing_trunk) {
05039          answer_trunk_chan(ringing_trunk->trunk->chan);
05040          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05041 
05042          free(ringing_trunk);
05043 
05044          /* Queue up reprocessing ringing trunks, and then ringing stations again */
05045          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05046          sla_queue_event(SLA_EVENT_DIAL_STATE);
05047       }
05048    }
05049 
05050    trunk_ref->chan = chan;
05051 
05052    if (!trunk_ref->trunk->chan) {
05053       ast_mutex_t cond_lock;
05054       ast_cond_t cond;
05055       pthread_t dont_care;
05056       struct dial_trunk_args args = {
05057          .trunk_ref = trunk_ref,
05058          .station = station,
05059          .cond_lock = &cond_lock,
05060          .cond = &cond,
05061       };
05062       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05063       /* Create a thread to dial the trunk and dump it into the conference.
05064        * However, we want to wait until the trunk has been dialed and the
05065        * conference is created before continuing on here. */
05066       ast_autoservice_start(chan);
05067       ast_mutex_init(&cond_lock);
05068       ast_cond_init(&cond, NULL);
05069       ast_mutex_lock(&cond_lock);
05070       ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
05071       ast_cond_wait(&cond, &cond_lock);
05072       ast_mutex_unlock(&cond_lock);
05073       ast_mutex_destroy(&cond_lock);
05074       ast_cond_destroy(&cond);
05075       ast_autoservice_stop(chan);
05076       if (!trunk_ref->trunk->chan) {
05077          ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
05078          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05079          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05080          trunk_ref->chan = NULL;
05081          ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05082          sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05083          return 0;
05084       }
05085    }
05086 
05087    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
05088       trunk_ref->trunk->on_hold) {
05089       trunk_ref->trunk->on_hold = 0;
05090       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
05091       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05092    }
05093 
05094    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05095    ast_set_flag(&conf_flags, 
05096       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05097    ast_answer(chan);
05098    conf = build_conf(conf_name, "", "", 0, 0, 1, chan);
05099    if (conf) {
05100       conf_run(chan, conf, conf_flags.flags, NULL);
05101       dispose_conf(conf);
05102       conf = NULL;
05103    }
05104    trunk_ref->chan = NULL;
05105    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05106       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05107       strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
05108       admin_exec(NULL, conf_name);
05109       trunk_ref->trunk->hold_stations = 0;
05110       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05111    }
05112    
05113    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
05114 
05115    ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05116    sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05117 
05118    return 0;
05119 }

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

Definition at line 4093 of file app_meetme.c.

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

Referenced by sla_calc_station_timeouts(), and sla_handle_dial_state_event().

04095 {
04096    struct sla_ringing_trunk *ringing_trunk;
04097    struct sla_trunk_ref *trunk_ref;
04098    struct sla_station_ref *station_ref;
04099 
04100    ast_dial_join(ringing_station->station->dial);
04101    ast_dial_destroy(ringing_station->station->dial);
04102    ringing_station->station->dial = NULL;
04103 
04104    if (hangup == SLA_STATION_HANGUP_NORMAL)
04105       goto done;
04106 
04107    /* If the station is being hung up because of a timeout, then add it to the
04108     * list of timed out stations on each of the ringing trunks.  This is so
04109     * that when doing further processing to figure out which stations should be
04110     * ringing, which trunk to answer, determining timeouts, etc., we know which
04111     * ringing trunks we should ignore. */
04112    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04113       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04114          if (ringing_trunk->trunk == trunk_ref->trunk)
04115             break;
04116       }
04117       if (!trunk_ref)
04118          continue;
04119       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
04120          continue;
04121       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
04122    }
04123 
04124 done:
04125    ast_free(ringing_station);
04126 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 4078 of file app_meetme.c.

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

Referenced by sla_calc_trunk_timeouts().

04079 {
04080    char buf[80];
04081    struct sla_station_ref *station_ref;
04082 
04083    snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
04084    admin_exec(NULL, buf);
04085    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04086 
04087    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
04088       ast_free(station_ref);
04089 
04090    ast_free(ringing_trunk);
04091 }

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

Definition at line 4766 of file app_meetme.c.

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

Referenced by sla_load_config().

04767 {
04768    struct sla_failed_station *failed_station;
04769    struct sla_ringing_station *ringing_station;
04770 
04771    ast_mutex_lock(&sla.lock);
04772 
04773    while (!sla.stop) {
04774       struct sla_event *event;
04775       struct timespec ts = { 0, };
04776       unsigned int have_timeout = 0;
04777 
04778       if (AST_LIST_EMPTY(&sla.event_q)) {
04779          if ((have_timeout = sla_process_timers(&ts)))
04780             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
04781          else
04782             ast_cond_wait(&sla.cond, &sla.lock);
04783          if (sla.stop)
04784             break;
04785       }
04786 
04787       if (have_timeout)
04788          sla_process_timers(NULL);
04789 
04790       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
04791          ast_mutex_unlock(&sla.lock);
04792          switch (event->type) {
04793          case SLA_EVENT_HOLD:
04794             sla_handle_hold_event(event);
04795             break;
04796          case SLA_EVENT_DIAL_STATE:
04797             sla_handle_dial_state_event();
04798             break;
04799          case SLA_EVENT_RINGING_TRUNK:
04800             sla_handle_ringing_trunk_event();
04801             break;
04802          case SLA_EVENT_RELOAD:
04803             sla.reload = 1;
04804          case SLA_EVENT_CHECK_RELOAD:
04805             break;
04806          }
04807          ast_free(event);
04808          ast_mutex_lock(&sla.lock);
04809       }
04810 
04811       if (sla.reload)
04812          sla_check_reload();
04813    }
04814 
04815    ast_mutex_unlock(&sla.lock);
04816 
04817    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
04818       ast_free(ringing_station);
04819 
04820    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
04821       ast_free(failed_station);
04822 
04823    return NULL;
04824 }

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

Definition at line 5167 of file app_meetme.c.

References ALL_TRUNK_REFS, AST_APP_ARG, ast_app_parse_options(), ast_atomic_fetchadd_int(), AST_CONTROL_RINGING, AST_DECLARE_APP_ARGS, ast_free, ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, build_conf(), sla_trunk::chan, chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, dispose_conf(), announce_listitem::entry, ast_flags::flags, LOG_ERROR, MAX_CONFNUM, sla_trunk::on_hold, OPT_ARG_ARRAY_SIZE, OPT_ARG_MOH_CLASS, parse(), pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), queue_ringing_trunk(), sla_trunk::ref_count, sla, sla_change_trunk_state(), SLA_EVENT_CHECK_RELOAD, SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), SLA_TRUNK_OPT_ARG_ARRAY_SIZE, SLA_TRUNK_OPT_ARG_MOH_CLASS, SLA_TRUNK_OPT_MOH, sla_trunk_opts, SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by load_module().

05168 {
05169    char conf_name[MAX_CONFNUM];
05170    struct ast_conference *conf;
05171    struct ast_flags conf_flags = { 0 };
05172    struct sla_trunk *trunk;
05173    struct sla_ringing_trunk *ringing_trunk;
05174    AST_DECLARE_APP_ARGS(args,
05175       AST_APP_ARG(trunk_name);
05176       AST_APP_ARG(options);
05177    );
05178    char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
05179    char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
05180    struct ast_flags opt_flags = { 0 };
05181    char *parse;
05182 
05183    if (ast_strlen_zero(data)) {
05184       ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
05185       return -1;
05186    }
05187 
05188    parse = ast_strdupa(data);
05189    AST_STANDARD_APP_ARGS(args, parse);
05190    if (args.argc == 2) {
05191       if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
05192          ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
05193          return -1;
05194       }
05195    }
05196 
05197    AST_RWLIST_RDLOCK(&sla_trunks);
05198    trunk = sla_find_trunk(args.trunk_name);
05199    if (trunk)
05200       ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
05201    AST_RWLIST_UNLOCK(&sla_trunks);
05202 
05203    if (!trunk) {
05204       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
05205       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05206       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05207       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05208       return 0;
05209    }
05210 
05211    if (trunk->chan) {
05212       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
05213          args.trunk_name);
05214       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05215       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05216       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05217       return 0;
05218    }
05219 
05220    trunk->chan = chan;
05221 
05222    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
05223       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05224       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05225       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05226       return 0;
05227    }
05228 
05229    snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
05230    conf = build_conf(conf_name, "", "", 1, 1, 1, chan);
05231    if (!conf) {
05232       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05233       ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05234       sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05235       return 0;
05236    }
05237    ast_set_flag(&conf_flags, 
05238       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
05239 
05240    if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
05241       ast_indicate(chan, -1);
05242       ast_set_flag(&conf_flags, CONFFLAG_MOH);
05243       conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
05244    } else
05245       ast_indicate(chan, AST_CONTROL_RINGING);
05246 
05247    conf_run(chan, conf, conf_flags.flags, opts);
05248    dispose_conf(conf);
05249    conf = NULL;
05250    trunk->chan = NULL;
05251    trunk->on_hold = 0;
05252 
05253    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05254 
05255    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
05256       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
05257 
05258    /* Remove the entry from the list of ringing trunks if it is still there. */
05259    ast_mutex_lock(&sla.lock);
05260    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05261       if (ringing_trunk->trunk == trunk) {
05262          AST_LIST_REMOVE_CURRENT(entry);
05263          break;
05264       }
05265    }
05266    AST_LIST_TRAVERSE_SAFE_END;
05267    ast_mutex_unlock(&sla.lock);
05268    if (ringing_trunk) {
05269       ast_free(ringing_trunk);
05270       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
05271       /* Queue reprocessing of ringing trunks to make stations stop ringing
05272        * that shouldn't be ringing after this trunk stopped. */
05273       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05274    }
05275 
05276    ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05277    sla_queue_event(SLA_EVENT_CHECK_RELOAD);  
05278 
05279    return 0;
05280 }

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

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

01225 {
01226 #define S(e) case e: return # e;
01227    switch (state) {
01228    S(SLA_TRUNK_STATE_IDLE)
01229    S(SLA_TRUNK_STATE_RINGING)
01230    S(SLA_TRUNK_STATE_UP)
01231    S(SLA_TRUNK_STATE_ONHOLD)
01232    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01233    }
01234    return "Uknown State";
01235 #undef S
01236 }

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

Definition at line 762 of file app_meetme.c.

References set_listen_volume(), tweak_volume(), and user.

Referenced by admin_exec(), and conf_run().

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

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

Definition at line 750 of file app_meetme.c.

References set_talk_volume(), tweak_volume(), and user.

Referenced by admin_exec(), and conf_run().

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

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

Definition at line 715 of file app_meetme.c.

References volume::desired, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

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

static int unload_module ( void   )  [static]

Definition at line 5706 of file app_meetme.c.

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

05707 {
05708    int res = 0;
05709    
05710    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05711    res = ast_manager_unregister("MeetmeMute");
05712    res |= ast_manager_unregister("MeetmeUnmute");
05713    res |= ast_manager_unregister("MeetmeList");
05714    res |= ast_unregister_application(app4);
05715    res |= ast_unregister_application(app3);
05716    res |= ast_unregister_application(app2);
05717    res |= ast_unregister_application(app);
05718    res |= ast_unregister_application(slastation_app);
05719    res |= ast_unregister_application(slatrunk_app);
05720 
05721    ast_devstate_prov_del("Meetme");
05722    ast_devstate_prov_del("SLA");
05723    
05724    sla_destroy();
05725 
05726    return res;
05727 }


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

Definition at line 5766 of file app_meetme.c.

const char* app = "MeetMe" [static]

Definition at line 211 of file app_meetme.c.

const char* app2 = "MeetMeCount" [static]

Definition at line 212 of file app_meetme.c.

Referenced by _macro_exec().

const char* app3 = "MeetMeAdmin" [static]

Definition at line 213 of file app_meetme.c.

const char* app4 = "MeetMeChannelAdmin" [static]

Definition at line 214 of file app_meetme.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 5766 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 619 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 628 of file app_meetme.c.

struct ast_cli_entry cli_meetme[] [static]

Initial value:

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

Definition at line 1314 of file app_meetme.c.

Referenced by load_module(), and unload_module().

ast_cond_t cond

Definition at line 610 of file app_meetme.c.

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

Definition at line 421 of file app_meetme.c.

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

const char* descrip [static]

Definition at line 234 of file app_meetme.c.

const char* descrip2 [static]

Definition at line 297 of file app_meetme.c.

const char* descrip3 [static]

Definition at line 305 of file app_meetme.c.

const char* descrip4 [static]

Definition at line 328 of file app_meetme.c.

int earlyalert [static]

Definition at line 228 of file app_meetme.c.

int endalert [static]

Definition at line 229 of file app_meetme.c.

struct { ... } event_q

struct { ... } failed_stations

struct sla_event* first

Definition at line 615 of file app_meetme.c.

struct sla_failed_station* first

Definition at line 614 of file app_meetme.c.

struct sla_ringing_station* first

Definition at line 613 of file app_meetme.c.

struct sla_ringing_trunk* first

Definition at line 612 of file app_meetme.c.

int fuzzystart [static]

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

struct sla_event* last

Definition at line 615 of file app_meetme.c.

struct sla_failed_station* last

Definition at line 614 of file app_meetme.c.

struct sla_ringing_station* last

Definition at line 613 of file app_meetme.c.

struct sla_ringing_trunk* last

Definition at line 612 of file app_meetme.c.

ast_mutex_t lock

Definition at line 611 of file app_meetme.c.

char mandescr_meetmelist[] [static]

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

Referenced by conf_exec().

static int reload

A reload has been requested

Definition at line 621 of file app_meetme.c.

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

struct { ... } ringing_stations

struct { ... } ringing_trunks

int rt_log_members [static]

Definition at line 232 of file app_meetme.c.

int rt_schedule [static]

Definition at line 226 of file app_meetme.c.

struct { ... } sla [static]

A structure for data used by the sla thread.

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

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

Definition at line 551 of file app_meetme.c.

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

struct ast_app_option sla_trunk_opts[128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, } [static]

Definition at line 5165 of file app_meetme.c.

Referenced by sla_trunk_exec().

const char* slastation_app = "SLAStation" [static]

Definition at line 215 of file app_meetme.c.

const char* slastation_desc [static]

Definition at line 336 of file app_meetme.c.

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

Definition at line 222 of file app_meetme.c.

const char* slatrunk_app = "SLATrunk" [static]

Definition at line 216 of file app_meetme.c.

const char* slatrunk_desc [static]

Definition at line 349 of file app_meetme.c.

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

Definition at line 223 of file app_meetme.c.

unsigned int stop

Definition at line 616 of file app_meetme.c.

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

Definition at line 218 of file app_meetme.c.

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

Definition at line 219 of file app_meetme.c.

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

Definition at line 220 of file app_meetme.c.

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

Definition at line 221 of file app_meetme.c.

pthread_t thread

The SLA thread ID

Definition at line 609 of file app_meetme.c.


Generated on Thu Jul 9 13:40:46 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7