Wed Oct 28 13:31:27 2009

Asterisk developer's documentation


app_meetme.c File Reference

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

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

Include dependency graph for app_meetme.c:

Go to the source code of this file.

Data Structures

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

Defines

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

Enumerations

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

Functions

static void __fini_sla_stations (void)
static void __fini_sla_trunks (void)
static void __init_sla_stations (void)
static void __init_sla_trunks (void)
static void __reg_module (void)
static void __unreg_module (void)
static int acf_meetme_info (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int acf_meetme_info_eval (const char *keyword, const struct ast_conference *conf)
static int action_meetmelist (struct mansession *s, const struct message *m)
static int action_meetmemute (struct mansession *s, const struct message *m)
static int action_meetmeunmute (struct mansession *s, const struct message *m)
static int admin_exec (struct ast_channel *chan, const char *data)
 The MeetMeadmin application.
static void * announce_thread (void *data)
static void answer_trunk_chan (struct ast_channel *chan)
static struct ast_conferencebuild_conf (const char *confno, const char *pin, const 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, const char *data)
 The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command).
static char * complete_meetmecmd (const char *line, const char *word, int pos, int state)
static int conf_exec (struct ast_channel *chan, const char *data)
 The meetme() application.
static void conf_flush (int fd, struct ast_channel *chan)
static int conf_free (struct ast_conference *conf)
 Remove the conference from the list and free it.
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, const char *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)
 Decrement reference counts, as incremented by find_conf().
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
static struct ast_conferencefind_conf_realtime (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags, int *too_early)
static struct ast_conf_userfind_user (struct ast_conference *conf, const char *callerident)
static const char * get_announce_filename (enum announcetypes type)
static const char * istalking (int x)
static int load_config (int reload)
static void load_config_meetme (void)
static int load_module (void)
static char * meetme_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * meetme_show_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int meetmemute (struct mansession *s, const struct message *m, int mute)
static enum ast_device_state meetmestate (const char *data)
 Callback for devicestate providers.
static struct sla_ringing_trunkqueue_ringing_trunk (struct sla_trunk *trunk)
static void * recordthread (void *args)
static int reload (void)
static void reset_volumes (struct ast_conf_user *user)
static int rt_extend_conf (const char *confno)
static void * run_station (void *data)
static int set_listen_volume (struct ast_conf_user *user, int volume)
static int set_talk_volume (struct ast_conf_user *user, int volume)
static void sla_add_trunk_to_station (struct sla_station *station, struct ast_variable *var)
static int sla_build_station (struct ast_config *cfg, const char *cat)
static int sla_build_trunk (struct ast_config *cfg, const char *cat)
static int sla_calc_station_delays (unsigned int *timeout)
 Calculate the ring delay for a station.
static int sla_calc_station_timeouts (unsigned int *timeout)
 Process station ring timeouts.
static int sla_calc_trunk_timeouts (unsigned int *timeout)
 Process trunk ring timeouts.
static void sla_change_trunk_state (const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
static int sla_check_device (const char *device)
static int sla_check_failed_station (const struct sla_station *station)
 Check to see if this station has failed to be dialed in the past minute.
static int sla_check_inuse_station (const struct sla_station *station)
 Check to see if a station is in use.
static void sla_check_reload (void)
 Check if we can do a reload of SLA, and do it if we can.
static int sla_check_ringing_station (const struct sla_station *station)
 Check to see if this station is already ringing.
static int sla_check_station_delay (struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
 Calculate the ring delay for a given ringing trunk on a station.
static int sla_check_station_hold_access (const struct sla_trunk *trunk, const struct sla_station *station)
static int sla_check_timed_out_station (const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
 Check to see if dialing this station already timed out for this ringing trunk.
static struct sla_trunk_refsla_choose_idle_trunk (const struct sla_station *station)
 For a given station, choose the highest priority idle trunk.
static struct sla_ringing_trunksla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int rm)
 Choose the highest priority ringing trunk for a station.
static struct sla_ringing_stationsla_create_ringing_station (struct sla_station *station)
static struct sla_station_refsla_create_station_ref (struct sla_station *station)
static void sla_destroy (void)
static void sla_dial_state_callback (struct ast_dial *dial)
static struct sla_stationsla_find_station (const char *name)
 Find an SLA station by name.
static struct sla_trunksla_find_trunk (const char *name)
 Find an SLA trunk by name.
static struct sla_trunk_refsla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk)
static struct sla_trunk_refsla_find_trunk_ref_byname (const struct sla_station *station, const char *name)
 Find a trunk reference on a station by name.
static void sla_handle_dial_state_event (void)
static void sla_handle_hold_event (struct sla_event *event)
static void sla_handle_ringing_trunk_event (void)
static void sla_hangup_stations (void)
static const char * sla_hold_str (unsigned int hold_access)
static int sla_load_config (int reload)
static int sla_process_timers (struct timespec *ts)
 Calculate the time until the next known event.
static void sla_queue_event (enum sla_event_type type)
static void sla_queue_event_conf (enum sla_event_type type, struct ast_channel *chan, struct ast_conference *conf)
 Queue a SLA event from the conference.
static void sla_queue_event_full (enum sla_event_type type, struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
static void sla_queue_event_nolock (enum sla_event_type type)
static int sla_ring_station (struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
 Ring a station.
static void sla_ring_stations (void)
 Ring stations based on current set of ringing trunks.
static char * sla_show_stations (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * sla_show_trunks (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static enum ast_device_state sla_state (const char *data)
static enum ast_device_state sla_state_to_devstate (enum sla_trunk_state state)
static int sla_station_exec (struct ast_channel *chan, const char *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, const char *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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static const char *const app = "MeetMe"
static const char *const app2 = "MeetMeCount"
static const char *const app3 = "MeetMeAdmin"
static const char *const app4 = "MeetMeChannelAdmin"
static struct ast_module_infoast_module_info = &__mod_info
static int audio_buffers
 The number of audio buffers to be allocated on pseudo channels when in a conference.
static struct ast_cli_entry cli_meetme []
static unsigned int conf_map [1024] = {0, }
static int earlyalert
static int endalert
static int extendby
static int fuzzystart
static const char gain_map []
static struct ast_custom_function meetme_info_acf
static struct ast_app_option meetme_opts [128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
static int rt_log_members
static int rt_schedule
struct {
   unsigned int   attempt_callerid:1
   ast_cond_t   cond
   struct {
      struct sla_event *   first
      struct sla_event *   last
   }   event_q
   struct {
      struct sla_failed_station *   first
      struct sla_failed_station *   last
   }   failed_stations
   ast_mutex_t   lock
   unsigned int   reload:1
   struct {
      struct sla_ringing_station *   first
      struct sla_ringing_station *   last
   }   ringing_stations
   struct {
      struct sla_ringing_trunk *   first
      struct sla_ringing_trunk *   last
   }   ringing_trunks
   unsigned int   stop:1
   pthread_t   thread
sla
 A structure for data used by the sla thread.
static const char sla_registrar [] = "SLA"
static struct ast_app_option sla_trunk_opts [128] = { [ 'M' ] = { .flag = SLA_TRUNK_OPT_MOH , .arg_index = SLA_TRUNK_OPT_ARG_MOH_CLASS + 1 }, }
static const char *const slastation_app = "SLAStation"
static const char *const slatrunk_app = "SLATrunk"


Detailed Description

Meet me conference bridge and Shared Line Appearances.

Author:
Mark Spencer <markster@digium.com>

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

Definition in file app_meetme.c.


Define Documentation

#define AST_FRAME_BITS   32

Definition at line 519 of file app_meetme.c.

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

#define CONF_SIZE   320

Definition at line 538 of file app_meetme.c.

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 499 of file app_meetme.c.

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

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

String format for scheduled conferences

Definition at line 506 of file app_meetme.c.

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

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 503 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

#define MAX_PIN   80

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

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

Referenced by meetme_show_cmd().

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 517 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 516 of file app_meetme.c.

Referenced by conf_run().

#define OPTIONS_LEN   100

Definition at line 661 of file app_meetme.c.

Referenced by find_conf_realtime().

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

Referenced by sms_readfile(), and trunkstate2str().

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 500 of file app_meetme.c.

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


Enumeration Type Documentation

anonymous enum

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

Definition at line 508 of file app_meetme.c.

00508      {
00509    ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
00510    ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
00511    ADMINFLAG_KICKME =    (1 << 3),  /*!< User has been kicked */
00512    /*! User has requested to speak */
00513    ADMINFLAG_T_REQUEST = (1 << 4),
00514 };

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

00540      {
00541    /*! user has admin access on the conference */
00542    CONFFLAG_ADMIN = (1 << 0),
00543    /*! If set the user can only receive audio from the conference */
00544    CONFFLAG_MONITOR = (1 << 1),
00545    /*! If set asterisk will exit conference when key defined in p() option is pressed */
00546    CONFFLAG_KEYEXIT = (1 << 2),
00547    /*! If set asterisk will provide a menu to the user when '*' is pressed */
00548    CONFFLAG_STARMENU = (1 << 3),
00549    /*! If set the use can only send audio to the conference */
00550    CONFFLAG_TALKER = (1 << 4),
00551    /*! If set there will be no enter or leave sounds */
00552    CONFFLAG_QUIET = (1 << 5),
00553    /*! If set, when user joins the conference, they will be told the number 
00554     *  of users that are already in */
00555    CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
00556    /*! Set to run AGI Script in Background */
00557    CONFFLAG_AGI = (1 << 7),
00558    /*! Set to have music on hold when user is alone in conference */
00559    CONFFLAG_MOH = (1 << 8),
00560    /*! If set the MeetMe will return if all marked with this flag left */
00561    CONFFLAG_MARKEDEXIT = (1 << 9),
00562    /*! If set, the MeetMe will wait until a marked user enters */
00563    CONFFLAG_WAITMARKED = (1 << 10),
00564    /*! If set, the MeetMe will exit to the specified context */
00565    CONFFLAG_EXIT_CONTEXT = (1 << 11),
00566    /*! If set, the user will be marked */
00567    CONFFLAG_MARKEDUSER = (1 << 12),
00568    /*! If set, user will be ask record name on entry of conference */
00569    CONFFLAG_INTROUSER = (1 << 13),
00570    /*! If set, the MeetMe will be recorded */
00571    CONFFLAG_RECORDCONF = (1<< 14),
00572    /*! If set, the user will be monitored if the user is talking or not */
00573    CONFFLAG_MONITORTALKER = (1 << 15),
00574    CONFFLAG_DYNAMIC = (1 << 16),
00575    CONFFLAG_DYNAMICPIN = (1 << 17),
00576    CONFFLAG_EMPTY = (1 << 18),
00577    CONFFLAG_EMPTYNOPIN = (1 << 19),
00578    CONFFLAG_ALWAYSPROMPT = (1 << 20),
00579    /*! If set, treat talking users as muted users */
00580    CONFFLAG_OPTIMIZETALKER = (1 << 21),
00581    /*! If set, won't speak the extra prompt when the first person 
00582     *  enters the conference */
00583    CONFFLAG_NOONLYPERSON = (1 << 22),
00584    /*! If set, user will be asked to record name on entry of conference 
00585     *  without review */
00586    CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
00587    /*! If set, the user will be initially self-muted */
00588    CONFFLAG_STARTMUTED = (1 << 24),
00589    /*! Pass DTMF through the conference */
00590    CONFFLAG_PASS_DTMF = (1 << 25),
00591    CONFFLAG_SLA_STATION = (1 << 26),
00592    CONFFLAG_SLA_TRUNK = (1 << 27),
00593    /*! If set, the user should continue in the dialplan if kicked out */
00594    CONFFLAG_KICK_CONTINUE = (1 << 28),
00595    CONFFLAG_DURATION_STOP = (1 << 29),
00596    CONFFLAG_DURATION_LIMIT = (1 << 30),
00597    /*! Do not write any audio to this channel until the state is up. */
00598    CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31),
00599 };

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

00601      {
00602    OPT_ARG_WAITMARKED = 0,
00603    OPT_ARG_EXITKEYS   = 1,
00604    OPT_ARG_DURATION_STOP = 2,
00605    OPT_ARG_DURATION_LIMIT = 3,
00606    OPT_ARG_MOH_CLASS = 4,
00607    OPT_ARG_ARRAY_SIZE = 5,
00608 };

anonymous enum

Enumerator:
SLA_TRUNK_OPT_MOH 

Definition at line 5851 of file app_meetme.c.

05851      {
05852    SLA_TRUNK_OPT_MOH = (1 << 0),
05853 };

anonymous enum

Enumerator:
SLA_TRUNK_OPT_ARG_MOH_CLASS 
SLA_TRUNK_OPT_ARG_ARRAY_SIZE 

Definition at line 5855 of file app_meetme.c.

05855      {
05856    SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
05857    SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
05858 };

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 663 of file app_meetme.c.

00663                    {
00664    CONF_HASJOIN,
00665    CONF_HASLEFT
00666 };

Enumerator:
ENTER 
LEAVE 

Definition at line 526 of file app_meetme.c.

00526                     {
00527    ENTER,
00528    LEAVE
00529 };

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 531 of file app_meetme.c.

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

Enumerator:
SLA_EVENT_HOLD  A station has put the call on hold
SLA_EVENT_DIAL_STATE  The state of a dial has changed
SLA_EVENT_RINGING_TRUNK  The state of a ringing trunk has changed
SLA_EVENT_RELOAD  A reload of configuration has been requested
SLA_EVENT_CHECK_RELOAD  Poke the SLA thread so it can check if it can perform a reload

Definition at line 856 of file app_meetme.c.

00856                     {
00857    /*! A station has put the call on hold */
00858    SLA_EVENT_HOLD,
00859    /*! The state of a dial has changed */
00860    SLA_EVENT_DIAL_STATE,
00861    /*! The state of a ringing trunk has changed */
00862    SLA_EVENT_RINGING_TRUNK,
00863    /*! A reload of configuration has been requested */
00864    SLA_EVENT_RELOAD,
00865    /*! Poke the SLA thread so it can check if it can perform a reload */
00866    SLA_EVENT_CHECK_RELOAD,
00867 };

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

00766                      {
00767    /*! This means that any station can put it on hold, and any station
00768     * can retrieve the call from hold. */
00769    SLA_HOLD_OPEN,
00770    /*! This means that only the station that put the call on hold may
00771     * retrieve it from hold. */
00772    SLA_HOLD_PRIVATE,
00773 };

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 893 of file app_meetme.c.

Enumerator:
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 758 of file app_meetme.c.

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 753 of file app_meetme.c.

00753                           {
00754    ALL_TRUNK_REFS,
00755    INACTIVE_TRUNK_REFS,
00756 };

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 521 of file app_meetme.c.

00521                    {
00522    VOL_UP,
00523    VOL_DOWN
00524 };


Function Documentation

static void __fini_sla_stations ( void   )  [static]

Definition at line 850 of file app_meetme.c.

00856 {

static void __fini_sla_trunks ( void   )  [static]

Definition at line 851 of file app_meetme.c.

00856 {

static void __init_sla_stations ( void   )  [static]

Definition at line 850 of file app_meetme.c.

00856 {

static void __init_sla_trunks ( void   )  [static]

Definition at line 851 of file app_meetme.c.

00856 {

static void __reg_module ( void   )  [static]

Definition at line 6542 of file app_meetme.c.

static void __unreg_module ( void   )  [static]

Definition at line 6542 of file app_meetme.c.

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

Definition at line 6411 of file app_meetme.c.

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

06412 {
06413    struct ast_conference *conf;
06414    char *parse;
06415    int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
06416    AST_DECLARE_APP_ARGS(args,
06417       AST_APP_ARG(keyword);
06418       AST_APP_ARG(confno);
06419    );
06420 
06421    if (ast_strlen_zero(data)) {
06422       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
06423       return -1;
06424    }
06425 
06426    parse = ast_strdupa(data);
06427    AST_STANDARD_APP_ARGS(args, parse);
06428 
06429    if (ast_strlen_zero(args.keyword)) {
06430       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
06431       return -1;
06432    }
06433 
06434    if (ast_strlen_zero(args.confno)) {
06435       ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
06436       return -1;
06437    }
06438 
06439    AST_LIST_LOCK(&confs);
06440    AST_LIST_TRAVERSE(&confs, conf, list) {
06441       if (!strcmp(args.confno, conf->confno)) {
06442          result = acf_meetme_info_eval(args.keyword, conf);
06443          break;
06444       }
06445    }
06446    AST_LIST_UNLOCK(&confs);
06447 
06448    if (result > -1) {
06449       snprintf(buf, len, "%d", result);
06450    } else if (result == -1) {
06451       snprintf(buf, len, "%s %s", "Error: invalid keyword:", args.keyword);
06452    } else if (result == -2) {
06453       snprintf(buf, len, "Error: conference (%s) not found", args.confno);
06454    }
06455 
06456    return 0;
06457 }

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

Definition at line 6393 of file app_meetme.c.

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

Referenced by acf_meetme_info().

06394 {
06395    if (!strcasecmp("lock", keyword)) {
06396       return conf->locked;
06397    } else if (!strcasecmp("parties", keyword)) {
06398       return conf->users;
06399    } else if (!strcasecmp("activity", keyword)) {
06400       time_t now;
06401       now = time(NULL);
06402       return (now - conf->start);
06403    } else if (!strcasecmp("dynamic", keyword)) {
06404       return conf->isdynamic;
06405    } else {
06406       return -1;
06407    }
06408 
06409 }

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

Definition at line 4348 of file app_meetme.c.

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

Referenced by load_module().

04349 {
04350    const char *actionid = astman_get_header(m, "ActionID");
04351    const char *conference = astman_get_header(m, "Conference");
04352    char idText[80] = "";
04353    struct ast_conference *cnf;
04354    struct ast_conf_user *user;
04355    int total = 0;
04356 
04357    if (!ast_strlen_zero(actionid))
04358       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04359 
04360    if (AST_LIST_EMPTY(&confs)) {
04361       astman_send_error(s, m, "No active conferences.");
04362       return 0;
04363    }
04364 
04365    astman_send_listack(s, m, "Meetme user list will follow", "start");
04366 
04367    /* Find the right conference */
04368    AST_LIST_LOCK(&confs);
04369    AST_LIST_TRAVERSE(&confs, cnf, list) {
04370       /* If we ask for one particular, and this isn't it, skip it */
04371       if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
04372          continue;
04373 
04374       /* Show all the users */
04375       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04376          total++;
04377          astman_append(s,
04378          "Event: MeetmeList\r\n"
04379          "%s"
04380          "Conference: %s\r\n"
04381          "UserNumber: %d\r\n"
04382          "CallerIDNum: %s\r\n"
04383          "CallerIDName: %s\r\n"
04384          "Channel: %s\r\n"
04385          "Admin: %s\r\n"
04386          "Role: %s\r\n"
04387          "MarkedUser: %s\r\n"
04388          "Muted: %s\r\n"
04389          "Talking: %s\r\n"
04390          "\r\n",
04391          idText,
04392          cnf->confno,
04393          user->user_no,
04394          S_OR(user->chan->cid.cid_num, "<unknown>"),
04395          S_OR(user->chan->cid.cid_name, "<no name>"),
04396          user->chan->name,
04397          user->userflags & CONFFLAG_ADMIN ? "Yes" : "No",
04398          user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen",
04399          user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No",
04400          user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
04401          user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored"); 
04402       }
04403    }
04404    AST_LIST_UNLOCK(&confs);
04405    /* Send final confirmation */
04406    astman_append(s,
04407    "Event: MeetmeListComplete\r\n"
04408    "EventList: Complete\r\n"
04409    "ListItems: %d\r\n"
04410    "%s"
04411    "\r\n", total, idText);
04412    return 0;
04413 }

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

Definition at line 4338 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04339 {
04340    return meetmemute(s, m, 1);
04341 }

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

Definition at line 4343 of file app_meetme.c.

References meetmemute().

Referenced by load_module().

04344 {
04345    return meetmemute(s, m, 0);
04346 }

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

The MeetMeadmin application.

MeetMeAdmin(confno, command, caller)

Definition at line 4033 of file app_meetme.c.

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

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

04033                                                                   {
04034    char *params;
04035    struct ast_conference *cnf;
04036    struct ast_conf_user *user = NULL;
04037    AST_DECLARE_APP_ARGS(args,
04038       AST_APP_ARG(confno);
04039       AST_APP_ARG(command);
04040       AST_APP_ARG(user);
04041    );
04042    int res = 0;
04043 
04044    if (ast_strlen_zero(data)) {
04045       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
04046       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04047       return -1;
04048    }
04049 
04050    params = ast_strdupa(data);
04051    AST_STANDARD_APP_ARGS(args, params);
04052 
04053    if (!args.command) {
04054       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
04055       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04056       return -1;
04057    }
04058 
04059    AST_LIST_LOCK(&confs);
04060    AST_LIST_TRAVERSE(&confs, cnf, list) {
04061       if (!strcmp(cnf->confno, args.confno))
04062          break;
04063    }
04064 
04065    if (!cnf) {
04066       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
04067       AST_LIST_UNLOCK(&confs);
04068       pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
04069       return 0;
04070    }
04071 
04072    ast_atomic_fetchadd_int(&cnf->refcount, 1);
04073 
04074    if (args.user)
04075       user = find_user(cnf, args.user);
04076 
04077    switch (*args.command) {
04078    case 76: /* L: Lock */ 
04079       cnf->locked = 1;
04080       break;
04081    case 108: /* l: Unlock */ 
04082       cnf->locked = 0;
04083       break;
04084    case 75: /* K: kick all users */
04085       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
04086          user->adminflags |= ADMINFLAG_KICKME;
04087       break;
04088    case 101: /* e: Eject last user*/
04089       user = AST_LIST_LAST(&cnf->userlist);
04090       if (!(user->userflags & CONFFLAG_ADMIN))
04091          user->adminflags |= ADMINFLAG_KICKME;
04092       else {
04093          res = -1;
04094          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
04095       }
04096       break;
04097    case 77: /* M: Mute */ 
04098       if (user) {
04099          user->adminflags |= ADMINFLAG_MUTED;
04100       } else {
04101          res = -2;
04102          ast_log(LOG_NOTICE, "Specified User not found!\n");
04103       }
04104       break;
04105    case 78: /* N: Mute all (non-admin) users */
04106       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04107          if (!(user->userflags & CONFFLAG_ADMIN)) {
04108             user->adminflags |= ADMINFLAG_MUTED;
04109          }
04110       }
04111       break;               
04112    case 109: /* m: Unmute */ 
04113       if (user) {
04114          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04115       } else {
04116          res = -2;
04117          ast_log(LOG_NOTICE, "Specified User not found!\n");
04118       }
04119       break;
04120    case 110: /* n: Unmute all users */
04121       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04122          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04123       }
04124       break;
04125    case 107: /* k: Kick user */ 
04126       if (user) {
04127          user->adminflags |= ADMINFLAG_KICKME;
04128       } else {
04129          res = -2;
04130          ast_log(LOG_NOTICE, "Specified User not found!\n");
04131       }
04132       break;
04133    case 118: /* v: Lower all users listen volume */
04134       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04135          tweak_listen_volume(user, VOL_DOWN);
04136       }
04137       break;
04138    case 86: /* V: Raise all users listen volume */
04139       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04140          tweak_listen_volume(user, VOL_UP);
04141       }
04142       break;
04143    case 115: /* s: Lower all users speaking volume */
04144       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04145          tweak_talk_volume(user, VOL_DOWN);
04146       }
04147       break;
04148    case 83: /* S: Raise all users speaking volume */
04149       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04150          tweak_talk_volume(user, VOL_UP);
04151       }
04152       break;
04153    case 82: /* R: Reset all volume levels */
04154       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04155          reset_volumes(user);
04156       }
04157       break;
04158    case 114: /* r: Reset user's volume level */
04159       if (user) {
04160          reset_volumes(user);
04161       } else {
04162          res = -2;
04163          ast_log(LOG_NOTICE, "Specified User not found!\n");
04164       }
04165       break;
04166    case 85: /* U: Raise user's listen volume */
04167       if (user) {
04168          tweak_listen_volume(user, VOL_UP);
04169       } else {
04170          res = -2;
04171          ast_log(LOG_NOTICE, "Specified User not found!\n");
04172       }
04173       break;
04174    case 117: /* u: Lower user's listen volume */
04175       if (user) {
04176          tweak_listen_volume(user, VOL_DOWN);
04177       } else {
04178          res = -2;
04179          ast_log(LOG_NOTICE, "Specified User not found!\n");
04180       }
04181       break;
04182    case 84: /* T: Raise user's talk volume */
04183       if (user) {
04184          tweak_talk_volume(user, VOL_UP);
04185       } else {
04186          res = -2;
04187          ast_log(LOG_NOTICE, "Specified User not found!\n");
04188       }
04189       break;
04190    case 116: /* t: Lower user's talk volume */
04191       if (user) {
04192          tweak_talk_volume(user, VOL_DOWN);
04193       } else {
04194          res = -2;
04195          ast_log(LOG_NOTICE, "Specified User not found!\n");
04196       }
04197       break;
04198    case 'E': /* E: Extend conference */
04199       if (rt_extend_conf(args.confno)) {
04200          res = -1;
04201       }
04202       break;
04203    }
04204 
04205    AST_LIST_UNLOCK(&confs);
04206 
04207    dispose_conf(cnf);
04208    pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
04209 
04210    return 0;
04211 }

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

Definition at line 1981 of file app_meetme.c.

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

Referenced by conf_run().

01982 {
01983    struct announce_listitem *current;
01984    struct ast_conference *conf = data;
01985    int res;
01986    char filename[PATH_MAX] = "";
01987    AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
01988    AST_LIST_HEAD_INIT_NOLOCK(&local_list);
01989 
01990    while (!conf->announcethread_stop) {
01991       ast_mutex_lock(&conf->announcelistlock);
01992       if (conf->announcethread_stop) {
01993          ast_mutex_unlock(&conf->announcelistlock);
01994          break;
01995       }
01996       if (AST_LIST_EMPTY(&conf->announcelist))
01997          ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
01998 
01999       AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
02000       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
02001 
02002       ast_mutex_unlock(&conf->announcelistlock);
02003       if (conf->announcethread_stop) {
02004          break;
02005       }
02006 
02007       for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
02008          ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
02009          if (!ast_fileexists(current->namerecloc, NULL, NULL))
02010             continue;
02011          if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
02012             if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
02013                res = ast_waitstream(current->confchan, "");
02014             if (!res) {
02015                ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
02016                if (!ast_streamfile(current->confchan, filename, current->language))
02017                   ast_waitstream(current->confchan, "");
02018             }
02019          }
02020          if (current->announcetype == CONF_HASLEFT) {
02021             ast_filedelete(current->namerecloc, NULL);
02022          }
02023       }
02024    }
02025 
02026    /* thread marked to stop, clean up */
02027    while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
02028       ast_filedelete(current->namerecloc, NULL);
02029       ao2_ref(current, -1);
02030    }
02031    return NULL;
02032 }

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

Definition at line 4723 of file app_meetme.c.

References ast_answer(), and ast_indicate().

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

04724 {
04725    ast_answer(chan);
04726    ast_indicate(chan, -1);
04727 }

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

Find or create a conference.

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

Definition at line 1132 of file app_meetme.c.

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

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

01135 {
01136    struct ast_conference *cnf;
01137    struct dahdi_confinfo dahdic = { 0, };
01138    int confno_int = 0;
01139 
01140    AST_LIST_LOCK(&confs);
01141 
01142    AST_LIST_TRAVERSE(&confs, cnf, list) {
01143       if (!strcmp(confno, cnf->confno)) 
01144          break;
01145    }
01146 
01147    if (cnf || (!make && !dynamic))
01148       goto cnfout;
01149 
01150    /* Make a new one */
01151    if (!(cnf = ast_calloc(1, sizeof(*cnf))))
01152       goto cnfout;
01153 
01154    ast_mutex_init(&cnf->playlock);
01155    ast_mutex_init(&cnf->listenlock);
01156    cnf->recordthread = AST_PTHREADT_NULL;
01157    ast_mutex_init(&cnf->recordthreadlock);
01158    cnf->announcethread = AST_PTHREADT_NULL;
01159    ast_mutex_init(&cnf->announcethreadlock);
01160    ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
01161    ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
01162    ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
01163    ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid));
01164 
01165    /* Setup a new dahdi conference */
01166    dahdic.confno = -1;
01167    dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01168    cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
01169    if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
01170       ast_log(LOG_WARNING, "Unable to open pseudo device\n");
01171       if (cnf->fd >= 0)
01172          close(cnf->fd);
01173       ast_free(cnf);
01174       cnf = NULL;
01175       goto cnfout;
01176    }
01177 
01178    cnf->dahdiconf = dahdic.confno;
01179 
01180    /* Setup a new channel for playback of audio files */
01181    cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, chan, "pseudo", NULL);
01182    if (cnf->chan) {
01183       ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
01184       ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
01185       dahdic.chan = 0;
01186       dahdic.confno = cnf->dahdiconf;
01187       dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01188       if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
01189          ast_log(LOG_WARNING, "Error setting conference\n");
01190          if (cnf->chan)
01191             ast_hangup(cnf->chan);
01192          else
01193             close(cnf->fd);
01194 
01195          ast_free(cnf);
01196          cnf = NULL;
01197          goto cnfout;
01198       }
01199    }
01200 
01201    /* Fill the conference struct */
01202    cnf->start = time(NULL);
01203    cnf->maxusers = 0x7fffffff;
01204    cnf->isdynamic = dynamic ? 1 : 0;
01205    ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
01206    AST_LIST_INSERT_HEAD(&confs, cnf, list);
01207 
01208    /* Reserve conference number in map */
01209    if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01210       conf_map[confno_int] = 1;
01211    
01212 cnfout:
01213    if (cnf)
01214       ast_atomic_fetchadd_int(&cnf->refcount, refcount);
01215 
01216    AST_LIST_UNLOCK(&confs);
01217 
01218    return cnf;
01219 }

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

Definition at line 2034 of file app_meetme.c.

References ast_channel::_state, AST_STATE_UP, and CONFFLAG_NO_AUDIO_UNTIL_UP.

Referenced by conf_run().

02035 {
02036    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02037       return 1;
02038    }
02039 
02040    return (chan->_state == AST_STATE_UP);
02041 }

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

Definition at line 966 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

00967 {
00968    int res;
00969    int x;
00970 
00971    while (len) {
00972       if (block) {
00973          x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
00974          res = ioctl(fd, DAHDI_IOMUX, &x);
00975       } else
00976          res = 0;
00977       if (res >= 0)
00978          res = write(fd, data, len);
00979       if (res < 1) {
00980          if (errno != EAGAIN) {
00981             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00982             return -1;
00983          } else
00984             return 0;
00985       }
00986       len -= res;
00987       data += res;
00988    }
00989 
00990    return 0;
00991 }

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

The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command).

Definition at line 4215 of file app_meetme.c.

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

Referenced by load_module().

04215                                                                           {
04216    char *params;
04217    struct ast_conference *conf = NULL;
04218    struct ast_conf_user *user = NULL;
04219    AST_DECLARE_APP_ARGS(args,
04220       AST_APP_ARG(channel);
04221       AST_APP_ARG(command);
04222    );
04223 
04224    if (ast_strlen_zero(data)) {
04225       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
04226       return -1;
04227    }
04228    
04229    params = ast_strdupa(data);
04230    AST_STANDARD_APP_ARGS(args, params);
04231 
04232    if (!args.channel) {
04233       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
04234       return -1;
04235    }
04236 
04237    if (!args.command) {
04238       ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
04239       return -1;
04240    }
04241 
04242    AST_LIST_LOCK(&confs);
04243    AST_LIST_TRAVERSE(&confs, conf, list) {
04244       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
04245          if (!strcmp(user->chan->name, args.channel))
04246             break;
04247       }
04248    }
04249    
04250    if (!user) {
04251       ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
04252       AST_LIST_UNLOCK(&confs);
04253       return 0;
04254    }
04255    
04256    /* perform the specified action */
04257    switch (*args.command) {
04258       case 77: /* M: Mute */ 
04259          user->adminflags |= ADMINFLAG_MUTED;
04260          break;
04261       case 109: /* m: Unmute */ 
04262          user->adminflags &= ~ADMINFLAG_MUTED;
04263          break;
04264       case 107: /* k: Kick user */ 
04265          user->adminflags |= ADMINFLAG_KICKME;
04266          break;
04267       default: /* unknown command */
04268          ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
04269          break;
04270    }
04271 
04272    AST_LIST_UNLOCK(&confs);
04273    
04274    return 0;
04275 }

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

Definition at line 1221 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(), and meetme_show_cmd().

01222 {
01223    static const char * const cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
01224 
01225    int len = strlen(word);
01226    int which = 0;
01227    struct ast_conference *cnf = NULL;
01228    struct ast_conf_user *usr = NULL;
01229    char *confno = NULL;
01230    char usrno[50] = "";
01231    char *myline, *ret = NULL;
01232    
01233    if (pos == 1) {      /* Command */
01234       return ast_cli_complete(word, cmds, state);
01235    } else if (pos == 2) {  /* Conference Number */
01236       AST_LIST_LOCK(&confs);
01237       AST_LIST_TRAVERSE(&confs, cnf, list) {
01238          if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
01239             ret = cnf->confno;
01240             break;
01241          }
01242       }
01243       ret = ast_strdup(ret); /* dup before releasing the lock */
01244       AST_LIST_UNLOCK(&confs);
01245       return ret;
01246    } else if (pos == 3) {
01247       /* User Number || Conf Command option*/
01248       if (strstr(line, "mute") || strstr(line, "kick")) {
01249          if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
01250             return ast_strdup("all");
01251          which++;
01252          AST_LIST_LOCK(&confs);
01253 
01254          /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
01255          myline = ast_strdupa(line);
01256          if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
01257             while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
01258                ;
01259          }
01260          
01261          AST_LIST_TRAVERSE(&confs, cnf, list) {
01262             if (!strcmp(confno, cnf->confno))
01263                 break;
01264          }
01265 
01266          if (cnf) {
01267             /* Search for the user */
01268             AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
01269                snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
01270                if (!strncasecmp(word, usrno, len) && ++which > state)
01271                   break;
01272             }
01273          }
01274          AST_LIST_UNLOCK(&confs);
01275          return usr ? ast_strdup(usrno) : NULL;
01276       }
01277    }
01278 
01279    return NULL;
01280 }

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

The meetme() application.

Definition at line 3757 of file app_meetme.c.

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

03758 {
03759    int res = -1;
03760    char confno[MAX_CONFNUM] = "";
03761    int allowretry = 0;
03762    int retrycnt = 0;
03763    struct ast_conference *cnf = NULL;
03764    struct ast_flags confflags = {0}, config_flags = { 0 };
03765    int dynamic = 0;
03766    int empty = 0, empty_no_pin = 0;
03767    int always_prompt = 0;
03768    const char *notdata;
03769    char *info, the_pin[MAX_PIN] = "";
03770    AST_DECLARE_APP_ARGS(args,
03771       AST_APP_ARG(confno);
03772       AST_APP_ARG(options);
03773       AST_APP_ARG(pin);
03774    );
03775    char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
03776 
03777    if (ast_strlen_zero(data)) {
03778       allowretry = 1;
03779       notdata = "";
03780    } else {
03781       notdata = data;
03782    }
03783    
03784    if (chan->_state != AST_STATE_UP)
03785       ast_answer(chan);
03786 
03787    info = ast_strdupa(notdata);
03788 
03789    AST_STANDARD_APP_ARGS(args, info);  
03790 
03791    if (args.confno) {
03792       ast_copy_string(confno, args.confno, sizeof(confno));
03793       if (ast_strlen_zero(confno)) {
03794          allowretry = 1;
03795       }
03796    }
03797    
03798    if (args.pin)
03799       ast_copy_string(the_pin, args.pin, sizeof(the_pin));
03800 
03801    if (args.options) {
03802       ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
03803       dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
03804       if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
03805          strcpy(the_pin, "q");
03806 
03807       empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
03808       empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
03809       always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
03810    }
03811 
03812    do {
03813       if (retrycnt > 3)
03814          allowretry = 0;
03815       if (empty) {
03816          int i;
03817          struct ast_config *cfg;
03818          struct ast_variable *var;
03819          int confno_int;
03820 
03821          /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
03822          if ((empty_no_pin) || (!dynamic)) {
03823             cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03824             if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03825                var = ast_variable_browse(cfg, "rooms");
03826                while (var) {
03827                   if (!strcasecmp(var->name, "conf")) {
03828                      char *stringp = ast_strdupa(var->value);
03829                      if (stringp) {
03830                         char *confno_tmp = strsep(&stringp, "|,");
03831                         int found = 0;
03832                         if (!dynamic) {
03833                            /* For static:  run through the list and see if this conference is empty */
03834                            AST_LIST_LOCK(&confs);
03835                            AST_LIST_TRAVERSE(&confs, cnf, list) {
03836                               if (!strcmp(confno_tmp, cnf->confno)) {
03837                                  /* The conference exists, therefore it's not empty */
03838                                  found = 1;
03839                                  break;
03840                               }
03841                            }
03842                            AST_LIST_UNLOCK(&confs);
03843                            if (!found) {
03844                               /* At this point, we have a confno_tmp (static conference) that is empty */
03845                               if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
03846                                  /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
03847                                   * Case 2:  empty_no_pin and pin is blank (but not NULL)
03848                                   * Case 3:  not empty_no_pin
03849                                   */
03850                                  ast_copy_string(confno, confno_tmp, sizeof(confno));
03851                                  break;
03852                                  /* XXX the map is not complete (but we do have a confno) */
03853                               }
03854                            }
03855                         }
03856                      }
03857                   }
03858                   var = var->next;
03859                }
03860                ast_config_destroy(cfg);
03861             }
03862          }
03863 
03864          /* Select first conference number not in use */
03865          if (ast_strlen_zero(confno) && dynamic) {
03866             AST_LIST_LOCK(&confs);
03867             for (i = 0; i < ARRAY_LEN(conf_map); i++) {
03868                if (!conf_map[i]) {
03869                   snprintf(confno, sizeof(confno), "%d", i);
03870                   conf_map[i] = 1;
03871                   break;
03872                }
03873             }
03874             AST_LIST_UNLOCK(&confs);
03875          }
03876 
03877          /* Not found? */
03878          if (ast_strlen_zero(confno)) {
03879             res = ast_streamfile(chan, "conf-noempty", chan->language);
03880             if (!res)
03881                ast_waitstream(chan, "");
03882          } else {
03883             if (sscanf(confno, "%30d", &confno_int) == 1) {
03884                if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
03885                   res = ast_streamfile(chan, "conf-enteringno", chan->language);
03886                   if (!res) {
03887                      ast_waitstream(chan, "");
03888                      res = ast_say_digits(chan, confno_int, "", chan->language);
03889                   }
03890                }
03891             } else {
03892                ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
03893             }
03894          }
03895       }
03896 
03897       while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
03898          /* Prompt user for conference number */
03899          res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
03900          if (res < 0) {
03901             /* Don't try to validate when we catch an error */
03902             confno[0] = '\0';
03903             allowretry = 0;
03904             break;
03905          }
03906       }
03907       if (!ast_strlen_zero(confno)) {
03908          /* Check the validity of the conference */
03909          cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
03910             sizeof(the_pin), 1, &confflags);
03911          if (!cnf) {
03912             int too_early = 0;
03913 
03914             cnf = find_conf_realtime(chan, confno, 1, dynamic, 
03915                the_pin, sizeof(the_pin), 1, &confflags,&too_early);
03916             if (rt_schedule && too_early)
03917                allowretry = 0;
03918          }
03919 
03920          if (!cnf) {
03921             if (allowretry) {
03922                confno[0] = '\0';
03923                res = ast_streamfile(chan, "conf-invalid", chan->language);
03924                if (!res)
03925                   ast_waitstream(chan, "");
03926                res = -1;
03927             }
03928          } else {
03929             if ((!ast_strlen_zero(cnf->pin) &&
03930                  !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
03931                 (!ast_strlen_zero(cnf->pinadmin) &&
03932                  ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
03933                char pin[MAX_PIN] = "";
03934                int j;
03935 
03936                /* Allow the pin to be retried up to 3 times */
03937                for (j = 0; j < 3; j++) {
03938                   if (*the_pin && (always_prompt == 0)) {
03939                      ast_copy_string(pin, the_pin, sizeof(pin));
03940                      res = 0;
03941                   } else {
03942                      /* Prompt user for pin if pin is required */
03943                      res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
03944                   }
03945                   if (res >= 0) {
03946                      if (!strcasecmp(pin, cnf->pin) ||
03947                          (!ast_strlen_zero(cnf->pinadmin) &&
03948                           !strcasecmp(pin, cnf->pinadmin))) {
03949                         /* Pin correct */
03950                         allowretry = 0;
03951                         if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
03952                            if (!ast_strlen_zero(cnf->adminopts)) {
03953                               char *opts = ast_strdupa(cnf->adminopts);
03954                               ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
03955                            }
03956                         } else {
03957                            if (!ast_strlen_zero(cnf->useropts)) {
03958                               char *opts = ast_strdupa(cnf->useropts);
03959                               ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
03960                            }
03961                         }
03962                         /* Run the conference */
03963                         ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
03964                         res = conf_run(chan, cnf, confflags.flags, optargs);
03965                         break;
03966                      } else {
03967                         /* Pin invalid */
03968                         if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
03969                            res = ast_waitstream(chan, AST_DIGIT_ANY);
03970                            ast_stopstream(chan);
03971                         } else {
03972                            ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
03973                            break;
03974                         }
03975                         if (res < 0)
03976                            break;
03977                         pin[0] = res;
03978                         pin[1] = '\0';
03979                         res = -1;
03980                         if (allowretry)
03981                            confno[0] = '\0';
03982                      }
03983                   } else {
03984                      /* failed when getting the pin */
03985                      res = -1;
03986                      allowretry = 0;
03987                      /* see if we need to get rid of the conference */
03988                      break;
03989                   }
03990 
03991                   /* Don't retry pin with a static pin */
03992                   if (*the_pin && (always_prompt == 0)) {
03993                      break;
03994                   }
03995                }
03996             } else {
03997                /* No pin required */
03998                allowretry = 0;
03999 
04000                /* Run the conference */
04001                res = conf_run(chan, cnf, confflags.flags, optargs);
04002             }
04003             dispose_conf(cnf);
04004             cnf = NULL;
04005          }
04006       }
04007    } while (allowretry);
04008 
04009    if (cnf)
04010       dispose_conf(cnf);
04011    
04012    return res;
04013 }

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

Definition at line 1690 of file app_meetme.c.

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

Referenced by conf_run().

01691 {
01692    int x;
01693 
01694    /* read any frames that may be waiting on the channel
01695       and throw them away
01696    */
01697    if (chan) {
01698       struct ast_frame *f;
01699 
01700       /* when no frames are available, this will wait
01701          for 1 millisecond maximum
01702       */
01703       while (ast_waitfor(chan, 1)) {
01704          f = ast_read(chan);
01705          if (f)
01706             ast_frfree(f);
01707          else /* channel was hung up or something else happened */
01708             break;
01709       }
01710    }
01711 
01712    /* flush any data sitting in the pseudo channel */
01713    x = DAHDI_FLUSH_ALL;
01714    if (ioctl(fd, DAHDI_FLUSH, &x))
01715       ast_log(LOG_WARNING, "Error flushing channel\n");
01716 
01717 }

static int conf_free ( struct ast_conference conf  )  [static]

Remove the conference from the list and free it.

We assume that this was called while holding conflock.

Definition at line 1722 of file app_meetme.c.

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

Referenced by dispose_conf().

01723 {
01724    int x;
01725    struct announce_listitem *item;
01726    
01727    AST_LIST_REMOVE(&confs, conf, list);
01728    manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01729 
01730    if (conf->recording == MEETME_RECORD_ACTIVE) {
01731       conf->recording = MEETME_RECORD_TERMINATE;
01732       AST_LIST_UNLOCK(&confs);
01733       while (1) {
01734          usleep(1);
01735          AST_LIST_LOCK(&confs);
01736          if (conf->recording == MEETME_RECORD_OFF)
01737             break;
01738          AST_LIST_UNLOCK(&confs);
01739       }
01740    }
01741 
01742    for (x = 0; x < AST_FRAME_BITS; x++) {
01743       if (conf->transframe[x])
01744          ast_frfree(conf->transframe[x]);
01745       if (conf->transpath[x])
01746          ast_translator_free_path(conf->transpath[x]);
01747    }
01748    if (conf->announcethread != AST_PTHREADT_NULL) {
01749       ast_mutex_lock(&conf->announcelistlock);
01750       conf->announcethread_stop = 1;
01751       ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01752       ast_cond_signal(&conf->announcelist_addition);
01753       ast_mutex_unlock(&conf->announcelistlock);
01754       pthread_join(conf->announcethread, NULL);
01755    
01756       while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01757          ast_filedelete(item->namerecloc, NULL);
01758          ao2_ref(item, -1);
01759       }
01760       ast_mutex_destroy(&conf->announcelistlock);
01761    }
01762    if (conf->origframe)
01763       ast_frfree(conf->origframe);
01764    if (conf->lchan)
01765       ast_hangup(conf->lchan);
01766    if (conf->chan)
01767       ast_hangup(conf->chan);
01768    if (conf->fd >= 0)
01769       close(conf->fd);
01770    if (conf->recordingfilename) {
01771       ast_free(conf->recordingfilename);
01772    }
01773    if (conf->recordingformat) {
01774       ast_free(conf->recordingformat);
01775    }
01776    ast_mutex_destroy(&conf->playlock);
01777    ast_mutex_destroy(&conf->listenlock);
01778    ast_mutex_destroy(&conf->recordthreadlock);
01779    ast_mutex_destroy(&conf->announcethreadlock);
01780    ast_free(conf);
01781 
01782    return 0;
01783 }

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

Definition at line 1084 of file app_meetme.c.

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

Referenced by conf_run().

01085 {
01086    unsigned char *data;
01087    int len;
01088    int res = -1;
01089 
01090    if (!ast_check_hangup(chan))
01091       res = ast_autoservice_start(chan);
01092 
01093    AST_LIST_LOCK(&confs);
01094 
01095    switch(sound) {
01096    case ENTER:
01097       data = enter;
01098       len = sizeof(enter);
01099       break;
01100    case LEAVE:
01101       data = leave;
01102       len = sizeof(leave);
01103       break;
01104    default:
01105       data = NULL;
01106       len = 0;
01107    }
01108    if (data) {
01109       careful_write(conf->fd, data, len, 1);
01110    }
01111 
01112    AST_LIST_UNLOCK(&confs);
01113 
01114    if (!res) 
01115       ast_autoservice_stop(chan);
01116 }

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

Definition at line 1785 of file app_meetme.c.

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

Referenced by conf_run().

01787 {
01788    struct ast_conf_user *user;
01789 
01790    AST_LIST_TRAVERSE(&conf->userlist, user, list) {
01791       if (user == sender)
01792          continue;
01793       if (ast_write(user->chan, f) < 0)
01794          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01795    }
01796 }

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

Definition at line 2043 of file app_meetme.c.

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

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

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

Definition at line 1951 of file app_meetme.c.

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

Referenced by conf_run().

01952 {
01953    char *original_moh;
01954 
01955    ast_channel_lock(chan);
01956    original_moh = ast_strdupa(chan->musicclass);
01957    ast_string_field_set(chan, musicclass, musicclass);
01958    ast_channel_unlock(chan);
01959 
01960    ast_moh_start(chan, original_moh, NULL);
01961 
01962    ast_channel_lock(chan);
01963    ast_string_field_set(chan, musicclass, original_moh);
01964    ast_channel_unlock(chan);
01965 }

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

The MeetmeCount application.

Definition at line 3711 of file app_meetme.c.

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

Referenced by load_module().

03712 {
03713    int res = 0;
03714    struct ast_conference *conf;
03715    int count;
03716    char *localdata;
03717    char val[80] = "0"; 
03718    AST_DECLARE_APP_ARGS(args,
03719       AST_APP_ARG(confno);
03720       AST_APP_ARG(varname);
03721    );
03722 
03723    if (ast_strlen_zero(data)) {
03724       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
03725       return -1;
03726    }
03727    
03728    if (!(localdata = ast_strdupa(data)))
03729       return -1;
03730 
03731    AST_STANDARD_APP_ARGS(args, localdata);
03732    
03733    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
03734 
03735    if (conf) {
03736       count = conf->users;
03737       dispose_conf(conf);
03738       conf = NULL;
03739    } else
03740       count = 0;
03741 
03742    if (!ast_strlen_zero(args.varname)) {
03743       /* have var so load it and exit */
03744       snprintf(val, sizeof(val), "%d", count);
03745       pbx_builtin_setvar_helper(chan, args.varname, val);
03746    } else {
03747       if (chan->_state != AST_STATE_UP) {
03748          ast_answer(chan);
03749       }
03750       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
03751    }
03752 
03753    return res;
03754 }

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

Definition at line 5818 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

05819 {
05820    struct sla_trunk_ref *trunk_ref;
05821 
05822    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
05823       return NULL;
05824 
05825    trunk_ref->trunk = trunk;
05826 
05827    return trunk_ref;
05828 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 6029 of file app_meetme.c.

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

Referenced by sla_build_station(), and sla_destroy().

06030 {
06031    struct sla_trunk_ref *trunk_ref;
06032 
06033    if (!ast_strlen_zero(station->autocontext)) {
06034       AST_RWLIST_RDLOCK(&sla_trunks);
06035       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06036          char exten[AST_MAX_EXTENSION];
06037          char hint[AST_MAX_APP];
06038          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06039          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06040          ast_context_remove_extension(station->autocontext, exten, 
06041             1, sla_registrar);
06042          ast_context_remove_extension(station->autocontext, hint, 
06043             PRIORITY_HINT, sla_registrar);
06044       }
06045       AST_RWLIST_UNLOCK(&sla_trunks);
06046    }
06047 
06048    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
06049       ast_free(trunk_ref);
06050 
06051    ast_string_field_free_memory(station);
06052    ast_free(station);
06053 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 6015 of file app_meetme.c.

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

Referenced by sla_build_trunk(), and sla_destroy().

06016 {
06017    struct sla_station_ref *station_ref;
06018 
06019    if (!ast_strlen_zero(trunk->autocontext))
06020       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
06021 
06022    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
06023       ast_free(station_ref);
06024 
06025    ast_string_field_free_memory(trunk);
06026    ast_free(trunk);
06027 }

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

Definition at line 5530 of file app_meetme.c.

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

Referenced by sla_station_exec().

05531 {
05532    struct dial_trunk_args *args = data;
05533    struct ast_dial *dial;
05534    char *tech, *tech_data;
05535    enum ast_dial_result dial_res;
05536    char conf_name[MAX_CONFNUM];
05537    struct ast_conference *conf;
05538    struct ast_flags conf_flags = { 0 };
05539    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
05540    const char *cid_name = NULL, *cid_num = NULL;
05541 
05542    if (!(dial = ast_dial_create())) {
05543       ast_mutex_lock(args->cond_lock);
05544       ast_cond_signal(args->cond);
05545       ast_mutex_unlock(args->cond_lock);
05546       return NULL;
05547    }
05548 
05549    tech_data = ast_strdupa(trunk_ref->trunk->device);
05550    tech = strsep(&tech_data, "/");
05551    if (ast_dial_append(dial, tech, tech_data) == -1) {
05552       ast_mutex_lock(args->cond_lock);
05553       ast_cond_signal(args->cond);
05554       ast_mutex_unlock(args->cond_lock);
05555       ast_dial_destroy(dial);
05556       return NULL;
05557    }
05558 
05559    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
05560       cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
05561       ast_free(trunk_ref->chan->cid.cid_name);
05562       trunk_ref->chan->cid.cid_name = NULL;
05563    }
05564    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
05565       cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
05566       ast_free(trunk_ref->chan->cid.cid_num);
05567       trunk_ref->chan->cid.cid_num = NULL;
05568    }
05569 
05570    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
05571 
05572    if (cid_name)
05573       trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
05574    if (cid_num)
05575       trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
05576 
05577    if (dial_res != AST_DIAL_RESULT_TRYING) {
05578       ast_mutex_lock(args->cond_lock);
05579       ast_cond_signal(args->cond);
05580       ast_mutex_unlock(args->cond_lock);
05581       ast_dial_destroy(dial);
05582       return NULL;
05583    }
05584 
05585    for (;;) {
05586       unsigned int done = 0;
05587       switch ((dial_res = ast_dial_state(dial))) {
05588       case AST_DIAL_RESULT_ANSWERED:
05589          trunk_ref->trunk->chan = ast_dial_answered(dial);
05590       case AST_DIAL_RESULT_HANGUP:
05591       case AST_DIAL_RESULT_INVALID:
05592       case AST_DIAL_RESULT_FAILED:
05593       case AST_DIAL_RESULT_TIMEOUT:
05594       case AST_DIAL_RESULT_UNANSWERED:
05595          done = 1;
05596       case AST_DIAL_RESULT_TRYING:
05597       case AST_DIAL_RESULT_RINGING:
05598       case AST_DIAL_RESULT_PROGRESS:
05599       case AST_DIAL_RESULT_PROCEEDING:
05600          break;
05601       }
05602       if (done)
05603          break;
05604    }
05605 
05606    if (!trunk_ref->trunk->chan) {
05607       ast_mutex_lock(args->cond_lock);
05608       ast_cond_signal(args->cond);
05609       ast_mutex_unlock(args->cond_lock);
05610       ast_dial_join(dial);
05611       ast_dial_destroy(dial);
05612       return NULL;
05613    }
05614 
05615    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05616    ast_set_flag(&conf_flags, 
05617       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
05618       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
05619    conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan);
05620 
05621    ast_mutex_lock(args->cond_lock);
05622    ast_cond_signal(args->cond);
05623    ast_mutex_unlock(args->cond_lock);
05624 
05625    if (conf) {
05626       conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
05627       dispose_conf(conf);
05628       conf = NULL;
05629    }
05630 
05631    /* If the trunk is going away, it is definitely now IDLE. */
05632    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05633 
05634    trunk_ref->trunk->chan = NULL;
05635    trunk_ref->trunk->on_hold = 0;
05636 
05637    ast_dial_join(dial);
05638    ast_dial_destroy(dial);
05639 
05640    return NULL;
05641 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Decrement reference counts, as incremented by find_conf().

Definition at line 1870 of file app_meetme.c.

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

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

01871 {
01872    int res = 0;
01873    int confno_int = 0;
01874 
01875    AST_LIST_LOCK(&confs);
01876    if (ast_atomic_dec_and_test(&conf->refcount)) {
01877       /* Take the conference room number out of an inuse state */
01878       if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
01879          conf_map[confno_int] = 0;
01880       }
01881       conf_free(conf);
01882       res = 1;
01883    }
01884    AST_LIST_UNLOCK(&confs);
01885 
01886    return res;
01887 }

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

Definition at line 3609 of file app_meetme.c.

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

Referenced by conf_exec(), and count_exec().

03611 {
03612    struct ast_config *cfg;
03613    struct ast_variable *var;
03614    struct ast_flags config_flags = { 0 };
03615    struct ast_conference *cnf;
03616    char *parse;
03617    AST_DECLARE_APP_ARGS(args,
03618       AST_APP_ARG(confno);
03619       AST_APP_ARG(pin);
03620       AST_APP_ARG(pinadmin);
03621    );
03622 
03623    /* Check first in the conference list */
03624    ast_debug(1, "The requested confno is '%s'?\n", confno);
03625    AST_LIST_LOCK(&confs);
03626    AST_LIST_TRAVERSE(&confs, cnf, list) {
03627       ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
03628       if (!strcmp(confno, cnf->confno)) 
03629          break;
03630    }
03631    if (cnf) {
03632       cnf->refcount += refcount;
03633    }
03634    AST_LIST_UNLOCK(&confs);
03635 
03636    if (!cnf) {
03637       if (dynamic) {
03638          /* No need to parse meetme.conf */
03639          ast_debug(1, "Building dynamic conference '%s'\n", confno);
03640          if (dynamic_pin) {
03641             if (dynamic_pin[0] == 'q') {
03642                /* Query the user to enter a PIN */
03643                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
03644                   return NULL;
03645             }
03646             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
03647          } else {
03648             cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
03649          }
03650       } else {
03651          /* Check the config */
03652          cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03653          if (!cfg) {
03654             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
03655             return NULL;
03656          } else if (cfg == CONFIG_STATUS_FILEINVALID) {
03657             ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
03658             return NULL;
03659          }
03660          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
03661             if (strcasecmp(var->name, "conf"))
03662                continue;
03663             
03664             if (!(parse = ast_strdupa(var->value)))
03665                return NULL;
03666             
03667             AST_STANDARD_APP_ARGS(args, parse);
03668             ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
03669             if (!strcasecmp(args.confno, confno)) {
03670                /* Bingo it's a valid conference */
03671                cnf = build_conf(args.confno,
03672                      S_OR(args.pin, ""),
03673                      S_OR(args.pinadmin, ""),
03674                      make, dynamic, refcount, chan);
03675                break;
03676             }
03677          }
03678          if (!var) {
03679             ast_debug(1, "%s isn't a valid conference\n", confno);
03680          }
03681          ast_config_destroy(cfg);
03682       }
03683    } else if (dynamic_pin) {
03684       /* Correct for the user selecting 'D' instead of 'd' to have
03685          someone join into a conference that has already been created
03686          with a pin. */
03687       if (dynamic_pin[0] == 'q') {
03688          dynamic_pin[0] = '\0';
03689       }
03690    }
03691 
03692    if (cnf) {
03693       if (confflags && !cnf->chan &&
03694           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03695           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03696          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03697          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03698       }
03699       
03700       if (confflags && !cnf->chan &&
03701           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03702          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03703          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03704       }
03705    }
03706 
03707    return cnf;
03708 }

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

Definition at line 3435 of file app_meetme.c.

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

Referenced by conf_exec().

03437 {
03438    struct ast_variable *var, *origvar;
03439    struct ast_conference *cnf;
03440 
03441    *too_early = 0;
03442 
03443    /* Check first in the conference list */
03444    AST_LIST_LOCK(&confs);
03445    AST_LIST_TRAVERSE(&confs, cnf, list) {
03446       if (!strcmp(confno, cnf->confno)) 
03447          break;
03448    }
03449    if (cnf) {
03450       cnf->refcount += refcount;
03451    }
03452    AST_LIST_UNLOCK(&confs);
03453 
03454    if (!cnf) {
03455       char *pin = NULL, *pinadmin = NULL; /* For temp use */
03456       int maxusers = 0;
03457       struct timeval now;
03458       char recordingfilename[256] = "";
03459       char recordingformat[11] = "";
03460       char currenttime[19] = "";
03461       char eatime[19] = "";
03462       char bookid[51] = "";
03463       char recordingtmp[AST_MAX_EXTENSION] = "";
03464       char useropts[OPTIONS_LEN + 1]; /* Used for RealTime conferences */
03465       char adminopts[OPTIONS_LEN + 1];
03466       struct ast_tm tm, etm;
03467       struct timeval endtime = { .tv_sec = 0 };
03468       const char *var2;
03469 
03470       if (rt_schedule) {
03471          now = ast_tvnow();
03472 
03473          ast_localtime(&now, &tm, NULL);
03474          ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03475 
03476          ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
03477 
03478          var = ast_load_realtime("meetme", "confno",
03479             confno, "starttime <= ", currenttime, "endtime >= ",
03480             currenttime, NULL);
03481 
03482          if (!var && fuzzystart) {
03483             now = ast_tvnow();
03484             now.tv_sec += fuzzystart;
03485 
03486             ast_localtime(&now, &tm, NULL);
03487             ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03488             var = ast_load_realtime("meetme", "confno",
03489                confno, "starttime <= ", currenttime, "endtime >= ",
03490                currenttime, NULL);
03491          }
03492 
03493          if (!var && earlyalert) {
03494             now = ast_tvnow();
03495             now.tv_sec += earlyalert;
03496             ast_localtime(&now, &etm, NULL);
03497             ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
03498             var = ast_load_realtime("meetme", "confno",
03499                confno, "starttime <= ", eatime, "endtime >= ",
03500                currenttime, NULL);
03501             if (var) {
03502                *too_early = 1;
03503             }
03504          }
03505 
03506       } else {
03507           var = ast_load_realtime("meetme", "confno", confno, NULL);
03508       }
03509 
03510       if (!var)
03511          return NULL;
03512 
03513       if (rt_schedule && *too_early) {
03514          /* Announce that the caller is early and exit */
03515          if (!ast_streamfile(chan, "conf-has-not-started", chan->language))
03516             ast_waitstream(chan, "");
03517          ast_variables_destroy(var);
03518          return NULL;
03519       }
03520 
03521       for (origvar = var; var; var = var->next) {
03522          if (!strcasecmp(var->name, "pin")) {
03523             pin = ast_strdupa(var->value);
03524          } else if (!strcasecmp(var->name, "adminpin")) {
03525             pinadmin = ast_strdupa(var->value);
03526          } else if (!strcasecmp(var->name, "bookId")) {
03527             ast_copy_string(bookid, var->value, sizeof(bookid));
03528          } else if (!strcasecmp(var->name, "opts")) {
03529             ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
03530          } else if (!strcasecmp(var->name, "maxusers")) {
03531             maxusers = atoi(var->value);
03532          } else if (!strcasecmp(var->name, "adminopts")) {
03533             ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
03534          } else if (!strcasecmp(var->name, "recordingfilename")) {
03535             ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
03536          } else if (!strcasecmp(var->name, "recordingformat")) {
03537             ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
03538          } else if (!strcasecmp(var->name, "endtime")) {
03539             struct ast_tm endtime_tm;
03540             ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
03541             endtime = ast_mktime(&endtime_tm, NULL);
03542          }
03543       }
03544 
03545       ast_variables_destroy(origvar);
03546 
03547       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
03548 
03549       if (cnf) {
03550          cnf->maxusers = maxusers;
03551          cnf->endalert = endalert;
03552          cnf->endtime = endtime.tv_sec;
03553          cnf->useropts = ast_strdup(useropts);
03554          cnf->adminopts = ast_strdup(adminopts);
03555          cnf->bookid = ast_strdup(bookid);
03556          cnf->recordingfilename = ast_strdup(recordingfilename);
03557          cnf->recordingformat = ast_strdup(recordingformat);
03558 
03559          if (strchr(cnf->useropts, 'r')) {
03560             if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */
03561                ast_channel_lock(chan);
03562                if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
03563                   ast_free(cnf->recordingfilename);
03564                   cnf->recordingfilename = ast_strdup(var2);
03565                }
03566                ast_channel_unlock(chan);
03567                if (ast_strlen_zero(cnf->recordingfilename)) {
03568                   snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, chan->uniqueid);
03569                   ast_free(cnf->recordingfilename);
03570                   cnf->recordingfilename = ast_strdup(recordingtmp);
03571                }
03572             }
03573             if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */
03574                ast_channel_lock(chan);
03575                if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
03576                   ast_free(cnf->recordingformat);
03577                   cnf->recordingformat = ast_strdup(var2);
03578                }
03579                ast_channel_unlock(chan);
03580                if (ast_strlen_zero(cnf->recordingformat)) {
03581                   ast_free(cnf->recordingformat);
03582                   cnf->recordingformat = ast_strdup("wav");
03583                }
03584             }
03585             ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
03586          }
03587       }
03588    }
03589 
03590    if (cnf) {
03591       if (confflags && !cnf->chan &&
03592           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03593           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03594          ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03595          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03596       }
03597       
03598       if (confflags && !cnf->chan &&
03599           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03600          ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03601          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03602       }
03603    }
03604 
03605    return cnf;
03606 }

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

Definition at line 4015 of file app_meetme.c.

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

Referenced by acf_mailbox_exists(), admin_exec(), advanced_options(), calltoken_required(), forward_message(), handle_cli_iax2_prune_realtime(), leave_voicemail(), pp_each_extension_helper(), requirecalltoken_mark_auto(), set_config(), setup_incoming_call(), vm_authenticate(), vm_box_exists(), and vm_execmain().

04016 {
04017    struct ast_conf_user *user = NULL;
04018    int cid;
04019    
04020    sscanf(callerident, "%30i", &cid);
04021    if (conf && callerident) {
04022       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
04023          if (cid == user->user_no)
04024             return user;
04025       }
04026    }
04027    return NULL;
04028 }

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

Definition at line 1967 of file app_meetme.c.

References CONF_HASJOIN, and CONF_HASLEFT.

Referenced by announce_thread().

01968 {
01969    switch (type) {
01970    case CONF_HASLEFT:
01971       return "conf-hasleft";
01972       break;
01973    case CONF_HASJOIN:
01974       return "conf-hasjoin";
01975       break;
01976    default:
01977       return "";
01978    }
01979 }

static const char* istalking ( int  x  )  [static]

Definition at line 956 of file app_meetme.c.

Referenced by meetme_show_cmd().

00957 {
00958    if (x > 0)
00959       return "(talking)";
00960    else if (x < 0)
00961       return "(unmonitored)";
00962    else 
00963       return "(not talking)";
00964 }

static int load_config ( int  reload  )  [static]

Definition at line 6466 of file app_meetme.c.

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

06467 {
06468    load_config_meetme();
06469 
06470    if (reload) {
06471       sla_queue_event(SLA_EVENT_RELOAD);
06472       ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
06473          "and will be completed when the system is idle.\n");
06474       return 0;
06475    }
06476    
06477    return sla_load_config(0);
06478 }

static void load_config_meetme ( void   )  [static]

Definition at line 4502 of file app_meetme.c.

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

Referenced by load_config().

04503 {
04504    struct ast_config *cfg;
04505    struct ast_flags config_flags = { 0 };
04506    const char *val;
04507 
04508    if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
04509       return;
04510    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04511       ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
04512       return;
04513    }
04514 
04515    audio_buffers = DEFAULT_AUDIO_BUFFERS;
04516 
04517    /*  Scheduling support is off by default */
04518    rt_schedule = 0;
04519    fuzzystart = 0;
04520    earlyalert = 0;
04521    endalert = 0;
04522    extendby = 0;
04523 
04524    /*  Logging of participants defaults to ON for compatibility reasons */
04525    rt_log_members = 1;  
04526 
04527    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
04528       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
04529          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
04530          audio_buffers = DEFAULT_AUDIO_BUFFERS;
04531       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
04532          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
04533             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
04534          audio_buffers = DEFAULT_AUDIO_BUFFERS;
04535       }
04536       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
04537          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
04538    }
04539 
04540    if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
04541       rt_schedule = ast_true(val);
04542    if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
04543       rt_log_members = ast_true(val);
04544    if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
04545       if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
04546          ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
04547          fuzzystart = 0;
04548       } 
04549    }
04550    if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
04551       if ((sscanf(val, "%30d", &earlyalert) != 1)) {
04552          ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
04553          earlyalert = 0;
04554       } 
04555    }
04556    if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
04557       if ((sscanf(val, "%30d", &endalert) != 1)) {
04558          ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
04559          endalert = 0;
04560       } 
04561    }
04562    if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
04563       if ((sscanf(val, "%30d", &extendby) != 1)) {
04564          ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
04565          extendby = 0;
04566       } 
04567    }
04568 
04569    ast_config_destroy(cfg);
04570 }

static int load_module ( void   )  [static]

Definition at line 6506 of file app_meetme.c.

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

06507 {
06508    int res = 0;
06509 
06510    res |= load_config(0);
06511 
06512    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
06513    res |= ast_manager_register_xml("MeetmeMute", EVENT_FLAG_CALL, action_meetmemute);
06514    res |= ast_manager_register_xml("MeetmeUnmute", EVENT_FLAG_CALL, action_meetmeunmute);
06515    res |= ast_manager_register_xml("MeetmeList", EVENT_FLAG_REPORTING, action_meetmelist);
06516    res |= ast_register_application_xml(app4, channel_admin_exec);
06517    res |= ast_register_application_xml(app3, admin_exec);
06518    res |= ast_register_application_xml(app2, count_exec);
06519    res |= ast_register_application_xml(app, conf_exec);
06520    res |= ast_register_application_xml(slastation_app, sla_station_exec);
06521    res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
06522 
06523    res |= ast_devstate_prov_add("Meetme", meetmestate);
06524    res |= ast_devstate_prov_add("SLA", sla_state);
06525 
06526    res |= ast_custom_function_register(&meetme_info_acf);
06527    ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
06528 
06529    return res;
06530 }

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

Definition at line 1436 of file app_meetme.c.

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

01437 {
01438    /* Process the command */
01439    struct ast_str *cmdline = NULL;
01440    int i = 0;
01441 
01442    switch (cmd) {
01443    case CLI_INIT:
01444       e->command = "meetme {lock|unlock|mute|unmute|kick}";
01445       e->usage =
01446          "Usage: meetme (un)lock|(un)mute|kick <confno> <usernumber>\n"
01447          "       Executes a command for the conference or on a conferee\n";
01448       return NULL;
01449    case CLI_GENERATE:
01450       return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01451    }
01452 
01453    if (a->argc > 8)
01454       ast_cli(a->fd, "Invalid Arguments.\n");
01455    /* Check for length so no buffer will overflow... */
01456    for (i = 0; i < a->argc; i++) {
01457       if (strlen(a->argv[i]) > 100)
01458          ast_cli(a->fd, "Invalid Arguments.\n");
01459    }
01460 
01461    /* Max confno length */
01462    if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01463       return CLI_FAILURE;
01464    }
01465 
01466    if (a->argc < 1) {
01467       ast_free(cmdline);
01468       return CLI_SHOWUSAGE;
01469    }
01470 
01471    ast_str_set(&cmdline, 0, "%s", a->argv[2]);  /* Argv 2: conference number */
01472    if (strstr(a->argv[1], "lock")) {
01473       if (strcmp(a->argv[1], "lock") == 0) {
01474          /* Lock */
01475          ast_str_append(&cmdline, 0, ",L");
01476       } else {
01477          /* Unlock */
01478          ast_str_append(&cmdline, 0, ",l");
01479       }
01480    } else if (strstr(a->argv[1], "mute")) { 
01481       if (a->argc < 4) {
01482          ast_free(cmdline);
01483          return CLI_SHOWUSAGE;
01484       }
01485       if (strcmp(a->argv[1], "mute") == 0) {
01486          /* Mute */
01487          if (strcmp(a->argv[3], "all") == 0) {
01488             ast_str_append(&cmdline, 0, ",N");
01489          } else {
01490             ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);  
01491          }
01492       } else {
01493          /* Unmute */
01494          if (strcmp(a->argv[3], "all") == 0) {
01495             ast_str_append(&cmdline, 0, ",n");
01496          } else {
01497             ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
01498          }
01499       }
01500    } else if (strcmp(a->argv[1], "kick") == 0) {
01501       if (a->argc < 4) {
01502          ast_free(cmdline);
01503          return CLI_SHOWUSAGE;
01504       }
01505       if (strcmp(a->argv[3], "all") == 0) {
01506          /* Kick all */
01507          ast_str_append(&cmdline, 0, ",K");
01508       } else {
01509          /* Kick a single user */
01510          ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
01511       }
01512    } else {
01513       ast_free(cmdline);
01514       return CLI_SHOWUSAGE;
01515    }
01516 
01517    ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
01518 
01519    admin_exec(NULL, ast_str_buffer(cmdline));
01520    ast_free(cmdline);
01521 
01522    return CLI_SUCCESS;
01523 }

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

Definition at line 1282 of file app_meetme.c.

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

01283 {
01284    /* Process the command */
01285    struct ast_conf_user *user;
01286    struct ast_conference *cnf;
01287    int hr, min, sec;
01288    int i = 0, total = 0;
01289    time_t now;
01290    struct ast_str *cmdline = NULL;
01291 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s  %-8s  %-6s\n"
01292 #define MC_DATA_FORMAT "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s  %-6s\n"
01293 
01294    switch (cmd) {
01295    case CLI_INIT:
01296       e->command = "meetme list [concise]";
01297       e->usage =
01298          "Usage: meetme list [concise] <confno> \n"
01299          "       List all or a specific conference.\n";
01300       return NULL;
01301    case CLI_GENERATE:
01302       return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01303    }
01304 
01305    /* Check for length so no buffer will overflow... */
01306    for (i = 0; i < a->argc; i++) {
01307       if (strlen(a->argv[i]) > 100)
01308          ast_cli(a->fd, "Invalid Arguments.\n");
01309    }
01310 
01311    /* Max confno length */
01312    if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01313       return CLI_FAILURE;
01314    }
01315 
01316    if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], "concise"))) {
01317       /* List all the conferences */   
01318       int concise = (a->argc == 3 && !strcasecmp(a->argv[2], "concise"));
01319       now = time(NULL);
01320       AST_LIST_LOCK(&confs);
01321       if (AST_LIST_EMPTY(&confs)) {
01322          if (!concise) {
01323             ast_cli(a->fd, "No active MeetMe conferences.\n");
01324          }
01325          AST_LIST_UNLOCK(&confs);
01326          ast_free(cmdline);
01327          return CLI_SUCCESS;
01328       }
01329       if (!concise) {
01330          ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
01331       }
01332       AST_LIST_TRAVERSE(&confs, cnf, list) {
01333          if (cnf->markedusers == 0) {
01334             ast_str_set(&cmdline, 0, "N/A ");
01335          } else {
01336             ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
01337          }
01338          hr = (now - cnf->start) / 3600;
01339          min = ((now - cnf->start) % 3600) / 60;
01340          sec = (now - cnf->start) % 60;
01341          if (!concise) {
01342             ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, ast_str_buffer(cmdline), hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
01343          } else {
01344             ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
01345                cnf->confno,
01346                cnf->users,
01347                cnf->markedusers,
01348                hr, min, sec,
01349                cnf->isdynamic,
01350                cnf->locked);
01351          }
01352 
01353          total += cnf->users;
01354       }
01355       AST_LIST_UNLOCK(&confs);
01356       if (!concise) {
01357          ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
01358       }
01359       ast_free(cmdline);
01360       return CLI_SUCCESS;
01361    } else if (strcmp(a->argv[1], "list") == 0) {
01362       int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
01363       /* List all the users in a conference */
01364       if (AST_LIST_EMPTY(&confs)) {
01365          if (!concise) {
01366             ast_cli(a->fd, "No active MeetMe conferences.\n");
01367          }
01368          ast_free(cmdline);
01369          return CLI_SUCCESS;  
01370       }
01371       /* Find the right conference */
01372       AST_LIST_LOCK(&confs);
01373       AST_LIST_TRAVERSE(&confs, cnf, list) {
01374          if (strcmp(cnf->confno, a->argv[2]) == 0) {
01375             break;
01376          }
01377       }
01378       if (!cnf) {
01379          if (!concise)
01380             ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
01381          AST_LIST_UNLOCK(&confs);
01382          ast_free(cmdline);
01383          return CLI_SUCCESS;
01384       }
01385       /* Show all the users */
01386       time(&now);
01387       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
01388          hr = (now - user->jointime) / 3600;
01389          min = ((now - user->jointime) % 3600) / 60;
01390          sec = (now - user->jointime) % 60;
01391          if (!concise) {
01392             ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
01393                user->user_no,
01394                S_OR(user->chan->cid.cid_num, "<unknown>"),
01395                S_OR(user->chan->cid.cid_name, "<no name>"),
01396                user->chan->name,
01397                user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
01398                user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
01399                user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
01400                user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
01401                istalking(user->talking), hr, min, sec); 
01402          } else {
01403             ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
01404                user->user_no,
01405                S_OR(user->chan->cid.cid_num, ""),
01406                S_OR(user->chan->cid.cid_name, ""),
01407                user->chan->name,
01408                user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
01409                user->userflags  & CONFFLAG_MONITOR ? "1" : "",
01410                user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
01411                user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
01412                user->talking, hr, min, sec);
01413          }
01414       }
01415       if (!concise) {
01416          ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
01417       }
01418       AST_LIST_UNLOCK(&confs);
01419       ast_free(cmdline);
01420       return CLI_SUCCESS;
01421    }
01422    if (a->argc < 2) {
01423       ast_free(cmdline);
01424       return CLI_SHOWUSAGE;
01425    }
01426 
01427    ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
01428 
01429    admin_exec(NULL, ast_str_buffer(cmdline));
01430    ast_free(cmdline);
01431 
01432    return CLI_SUCCESS;
01433 }

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

Definition at line 4277 of file app_meetme.c.

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

Referenced by action_meetmemute(), and action_meetmeunmute().

04278 {
04279    struct ast_conference *conf;
04280    struct ast_conf_user *user;
04281    const char *confid = astman_get_header(m, "Meetme");
04282    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
04283    int userno;
04284 
04285    if (ast_strlen_zero(confid)) {
04286       astman_send_error(s, m, "Meetme conference not specified");
04287       return 0;
04288    }
04289 
04290    if (ast_strlen_zero(userid)) {
04291       astman_send_error(s, m, "Meetme user number not specified");
04292       return 0;
04293    }
04294 
04295    userno = strtoul(userid, &userid, 10);
04296 
04297    if (*userid) {
04298       astman_send_error(s, m, "Invalid user number");
04299       return 0;
04300    }
04301 
04302    /* Look in the conference list */
04303    AST_LIST_LOCK(&confs);
04304    AST_LIST_TRAVERSE(&confs, conf, list) {
04305       if (!strcmp(confid, conf->confno))
04306          break;
04307    }
04308 
04309    if (!conf) {
04310       AST_LIST_UNLOCK(&confs);
04311       astman_send_error(s, m, "Meetme conference does not exist");
04312       return 0;
04313    }
04314 
04315    AST_LIST_TRAVERSE(&conf->userlist, user, list)
04316       if (user->user_no == userno)
04317          break;
04318 
04319    if (!user) {
04320       AST_LIST_UNLOCK(&confs);
04321       astman_send_error(s, m, "User number not found");
04322       return 0;
04323    }
04324 
04325    if (mute)
04326       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
04327    else
04328       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
04329 
04330    AST_LIST_UNLOCK(&confs);
04331 
04332    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);
04333 
04334    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
04335    return 0;
04336 }

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

Callback for devicestate providers.

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

04481 {
04482    struct ast_conference *conf;
04483 
04484    /* Find conference */
04485    AST_LIST_LOCK(&confs);
04486    AST_LIST_TRAVERSE(&confs, conf, list) {
04487       if (!strcmp(data, conf->confno))
04488          break;
04489    }
04490    AST_LIST_UNLOCK(&confs);
04491    if (!conf)
04492       return AST_DEVICE_INVALID;
04493 
04494 
04495    /* SKREP to fill */
04496    if (!conf->users)
04497       return AST_DEVICE_NOT_INUSE;
04498 
04499    return AST_DEVICE_INUSE;
04500 }

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

Definition at line 5830 of file app_meetme.c.

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

Referenced by sla_trunk_exec().

05831 {
05832    struct sla_ringing_trunk *ringing_trunk;
05833 
05834    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
05835       return NULL;
05836    
05837    ringing_trunk->trunk = trunk;
05838    ringing_trunk->ring_begin = ast_tvnow();
05839 
05840    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
05841 
05842    ast_mutex_lock(&sla.lock);
05843    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
05844    ast_mutex_unlock(&sla.lock);
05845 
05846    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05847 
05848    return ringing_trunk;
05849 }

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

Definition at line 4415 of file app_meetme.c.

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

04416 {
04417    struct ast_conference *cnf = args;
04418    struct ast_frame *f = NULL;
04419    int flags;
04420    struct ast_filestream *s = NULL;
04421    int res = 0;
04422    int x;
04423    const char *oldrecordingfilename = NULL;
04424 
04425    if (!cnf || !cnf->lchan) {
04426       pthread_exit(0);
04427    }
04428 
04429    ast_stopstream(cnf->lchan);
04430    flags = O_CREAT | O_TRUNC | O_WRONLY;
04431 
04432 
04433    cnf->recording = MEETME_RECORD_ACTIVE;
04434    while (ast_waitfor(cnf->lchan, -1) > -1) {
04435       if (cnf->recording == MEETME_RECORD_TERMINATE) {
04436          AST_LIST_LOCK(&confs);
04437          AST_LIST_UNLOCK(&confs);
04438          break;
04439       }
04440       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
04441          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
04442          oldrecordingfilename = cnf->recordingfilename;
04443       }
04444       
04445       f = ast_read(cnf->lchan);
04446       if (!f) {
04447          res = -1;
04448          break;
04449       }
04450       if (f->frametype == AST_FRAME_VOICE) {
04451          ast_mutex_lock(&cnf->listenlock);
04452          for (x = 0; x < AST_FRAME_BITS; x++) {
04453             /* Free any translations that have occured */
04454             if (cnf->transframe[x]) {
04455                ast_frfree(cnf->transframe[x]);
04456                cnf->transframe[x] = NULL;
04457             }
04458          }
04459          if (cnf->origframe)
04460             ast_frfree(cnf->origframe);
04461          cnf->origframe = ast_frdup(f);
04462          ast_mutex_unlock(&cnf->listenlock);
04463          if (s)
04464             res = ast_writestream(s, f);
04465          if (res) {
04466             ast_frfree(f);
04467             break;
04468          }
04469       }
04470       ast_frfree(f);
04471    }
04472    cnf->recording = MEETME_RECORD_OFF;
04473    if (s)
04474       ast_closestream(s);
04475    
04476    pthread_exit(0);
04477 }

static int reload ( void   )  [static]

Definition at line 6532 of file app_meetme.c.

References ast_unload_realtime(), and load_config().

06533 {
06534    ast_unload_realtime("meetme");
06535    return load_config(1);
06536 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 1076 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

01077 {
01078    signed char zero_volume = 0;
01079 
01080    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
01081    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
01082 }

static int rt_extend_conf ( const char *  confno  )  [static]

Definition at line 1889 of file app_meetme.c.

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

Referenced by admin_exec(), and conf_run().

01890 {
01891    char currenttime[32];
01892    char endtime[32];
01893    struct timeval now;
01894    struct ast_tm tm;
01895    struct ast_variable *var, *orig_var;
01896    char bookid[51];
01897 
01898    if (!extendby) {
01899       return 0;
01900    }
01901 
01902    now = ast_tvnow();
01903 
01904    ast_localtime(&now, &tm, NULL);
01905    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
01906 
01907    var = ast_load_realtime("meetme", "confno",
01908       confno, "startTime<= ", currenttime,
01909       "endtime>= ", currenttime, NULL);
01910 
01911    orig_var = var;
01912 
01913    /* Identify the specific RealTime conference */
01914    while (var) {
01915       if (!strcasecmp(var->name, "bookid")) {
01916          ast_copy_string(bookid, var->value, sizeof(bookid));
01917       }
01918       if (!strcasecmp(var->name, "endtime")) {
01919          ast_copy_string(endtime, var->value, sizeof(endtime));
01920       }
01921 
01922       var = var->next;
01923    }
01924    ast_variables_destroy(orig_var);
01925 
01926    ast_strptime(endtime, DATE_FORMAT, &tm);
01927    now = ast_mktime(&tm, NULL);
01928 
01929    now.tv_sec += extendby;
01930 
01931    ast_localtime(&now, &tm, NULL);
01932    ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
01933    strcat(currenttime, "0"); /* Seconds needs to be 00 */
01934 
01935    var = ast_load_realtime("meetme", "confno",
01936       confno, "startTime<= ", currenttime,
01937       "endtime>= ", currenttime, NULL);
01938 
01939    /* If there is no conflict with extending the conference, update the DB */
01940    if (!var) {
01941       ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
01942       ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
01943       return 0;
01944 
01945    }
01946 
01947    ast_variables_destroy(var);
01948    return -1;
01949 }

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

Definition at line 4729 of file app_meetme.c.

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

Referenced by sla_handle_dial_state_event().

04730 {
04731    struct sla_station *station;
04732    struct sla_trunk_ref *trunk_ref;
04733    struct ast_str *conf_name = ast_str_create(16);
04734    struct ast_flags conf_flags = { 0 };
04735    struct ast_conference *conf;
04736 
04737    {
04738       struct run_station_args *args = data;
04739       station = args->station;
04740       trunk_ref = args->trunk_ref;
04741       ast_mutex_lock(args->cond_lock);
04742       ast_cond_signal(args->cond);
04743       ast_mutex_unlock(args->cond_lock);
04744       /* args is no longer valid here. */
04745    }
04746 
04747    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
04748    ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
04749    ast_set_flag(&conf_flags, 
04750       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04751    answer_trunk_chan(trunk_ref->chan);
04752    conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan);
04753    if (conf) {
04754       conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
04755       dispose_conf(conf);
04756       conf = NULL;
04757    }
04758    trunk_ref->chan = NULL;
04759    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04760       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04761       ast_str_append(&conf_name, 0, ",K");
04762       admin_exec(NULL, ast_str_buffer(conf_name));
04763       trunk_ref->trunk->hold_stations = 0;
04764       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04765    }
04766 
04767    ast_dial_join(station->dial);
04768    ast_dial_destroy(station->dial);
04769    station->dial = NULL;
04770    ast_free(conf_name);
04771 
04772    return NULL;
04773 }

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

Definition at line 1005 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

01006 {
01007    char gain_adjust;
01008 
01009    /* attempt to make the adjustment in the channel driver;
01010       if successful, don't adjust in the frame reading routine
01011    */
01012    gain_adjust = gain_map[volume + 5];
01013 
01014    return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
01015 }

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

Definition at line 993 of file app_meetme.c.

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

Referenced by conf_run(), and tweak_talk_volume().

00994 {
00995    char gain_adjust;
00996 
00997    /* attempt to make the adjustment in the channel driver;
00998       if successful, don't adjust in the frame reading routine
00999    */
01000    gain_adjust = gain_map[volume + 5];
01001 
01002    return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
01003 }

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

Definition at line 6176 of file app_meetme.c.

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

Referenced by sla_build_station().

06177 {
06178    struct sla_trunk *trunk;
06179    struct sla_trunk_ref *trunk_ref;
06180    struct sla_station_ref *station_ref;
06181    char *trunk_name, *options, *cur;
06182 
06183    options = ast_strdupa(var->value);
06184    trunk_name = strsep(&options, ",");
06185    
06186    AST_RWLIST_RDLOCK(&sla_trunks);
06187    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
06188       if (!strcasecmp(trunk->name, trunk_name))
06189          break;
06190    }
06191 
06192    AST_RWLIST_UNLOCK(&sla_trunks);
06193    if (!trunk) {
06194       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
06195       return;
06196    }
06197    if (!(trunk_ref = create_trunk_ref(trunk)))
06198       return;
06199    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
06200 
06201    while ((cur = strsep(&options, ","))) {
06202       char *name, *value = cur;
06203       name = strsep(&value, "=");
06204       if (!strcasecmp(name, "ringtimeout")) {
06205          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
06206             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
06207                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06208             trunk_ref->ring_timeout = 0;
06209          }
06210       } else if (!strcasecmp(name, "ringdelay")) {
06211          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
06212             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
06213                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06214             trunk_ref->ring_delay = 0;
06215          }
06216       } else {
06217          ast_log(LOG_WARNING, "Invalid option '%s' for "
06218             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
06219       }
06220    }
06221 
06222    if (!(station_ref = sla_create_station_ref(station))) {
06223       ast_free(trunk_ref);
06224       return;
06225    }
06226    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
06227    AST_RWLIST_WRLOCK(&sla_trunks);
06228    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
06229    AST_RWLIST_UNLOCK(&sla_trunks);
06230    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
06231 }

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

Definition at line 6233 of file app_meetme.c.

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

Referenced by sla_load_config().

06234 {
06235    struct sla_station *station;
06236    struct ast_variable *var;
06237    const char *dev;
06238 
06239    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06240       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
06241       return -1;
06242    }
06243 
06244    if (!(station = ast_calloc(1, sizeof(*station))))
06245       return -1;
06246    if (ast_string_field_init(station, 32)) {
06247       ast_free(station);
06248       return -1;
06249    }
06250 
06251    ast_string_field_set(station, name, cat);
06252    ast_string_field_set(station, device, dev);
06253 
06254    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06255       if (!strcasecmp(var->name, "trunk"))
06256          sla_add_trunk_to_station(station, var);
06257       else if (!strcasecmp(var->name, "autocontext"))
06258          ast_string_field_set(station, autocontext, var->value);
06259       else if (!strcasecmp(var->name, "ringtimeout")) {
06260          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
06261             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
06262                var->value, station->name);
06263             station->ring_timeout = 0;
06264          }
06265       } else if (!strcasecmp(var->name, "ringdelay")) {
06266          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
06267             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
06268                var->value, station->name);
06269             station->ring_delay = 0;
06270          }
06271       } else if (!strcasecmp(var->name, "hold")) {
06272          if (!strcasecmp(var->value, "private"))
06273             station->hold_access = SLA_HOLD_PRIVATE;
06274          else if (!strcasecmp(var->value, "open"))
06275             station->hold_access = SLA_HOLD_OPEN;
06276          else {
06277             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
06278                var->value, station->name);
06279          }
06280 
06281       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06282          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06283             var->name, var->lineno, SLA_CONFIG_FILE);
06284       }
06285    }
06286 
06287    if (!ast_strlen_zero(station->autocontext)) {
06288       struct ast_context *context;
06289       struct sla_trunk_ref *trunk_ref;
06290       context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
06291       if (!context) {
06292          ast_log(LOG_ERROR, "Failed to automatically find or create "
06293             "context '%s' for SLA!\n", station->autocontext);
06294          destroy_station(station);
06295          return -1;
06296       }
06297       /* The extension for when the handset goes off-hook.
06298        * exten => station1,1,SLAStation(station1) */
06299       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
06300          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
06301          ast_log(LOG_ERROR, "Failed to automatically create extension "
06302             "for trunk '%s'!\n", station->name);
06303          destroy_station(station);
06304          return -1;
06305       }
06306       AST_RWLIST_RDLOCK(&sla_trunks);
06307       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06308          char exten[AST_MAX_EXTENSION];
06309          char hint[AST_MAX_APP];
06310          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06311          snprintf(hint, sizeof(hint), "SLA:%s", exten);
06312          /* Extension for this line button 
06313           * exten => station1_line1,1,SLAStation(station1_line1) */
06314          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
06315             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
06316             ast_log(LOG_ERROR, "Failed to automatically create extension "
06317                "for trunk '%s'!\n", station->name);
06318             destroy_station(station);
06319             return -1;
06320          }
06321          /* Hint for this line button 
06322           * exten => station1_line1,hint,SLA:station1_line1 */
06323          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
06324             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
06325             ast_log(LOG_ERROR, "Failed to automatically create hint "
06326                "for trunk '%s'!\n", station->name);
06327             destroy_station(station);
06328             return -1;
06329          }
06330       }
06331       AST_RWLIST_UNLOCK(&sla_trunks);
06332    }
06333 
06334    AST_RWLIST_WRLOCK(&sla_stations);
06335    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
06336    AST_RWLIST_UNLOCK(&sla_stations);
06337 
06338    return 0;
06339 }

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

Definition at line 6098 of file app_meetme.c.

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

Referenced by sla_load_config().

06099 {
06100    struct sla_trunk *trunk;
06101    struct ast_variable *var;
06102    const char *dev;
06103 
06104    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06105       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
06106       return -1;
06107    }
06108 
06109    if (sla_check_device(dev)) {
06110       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
06111          cat, dev);
06112       return -1;
06113    }
06114 
06115    if (!(trunk = ast_calloc(1, sizeof(*trunk))))
06116       return -1;
06117    if (ast_string_field_init(trunk, 32)) {
06118       ast_free(trunk);
06119       return -1;
06120    }
06121 
06122    ast_string_field_set(trunk, name, cat);
06123    ast_string_field_set(trunk, device, dev);
06124 
06125    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06126       if (!strcasecmp(var->name, "autocontext"))
06127          ast_string_field_set(trunk, autocontext, var->value);
06128       else if (!strcasecmp(var->name, "ringtimeout")) {
06129          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
06130             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
06131                var->value, trunk->name);
06132             trunk->ring_timeout = 0;
06133          }
06134       } else if (!strcasecmp(var->name, "barge"))
06135          trunk->barge_disabled = ast_false(var->value);
06136       else if (!strcasecmp(var->name, "hold")) {
06137          if (!strcasecmp(var->value, "private"))
06138             trunk->hold_access = SLA_HOLD_PRIVATE;
06139          else if (!strcasecmp(var->value, "open"))
06140             trunk->hold_access = SLA_HOLD_OPEN;
06141          else {
06142             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
06143                var->value, trunk->name);
06144          }
06145       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06146          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06147             var->name, var->lineno, SLA_CONFIG_FILE);
06148       }
06149    }
06150 
06151    if (!ast_strlen_zero(trunk->autocontext)) {
06152       struct ast_context *context;
06153       context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
06154       if (!context) {
06155          ast_log(LOG_ERROR, "Failed to automatically find or create "
06156             "context '%s' for SLA!\n", trunk->autocontext);
06157          destroy_trunk(trunk);
06158          return -1;
06159       }
06160       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
06161          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
06162          ast_log(LOG_ERROR, "Failed to automatically create extension "
06163             "for trunk '%s'!\n", trunk->name);
06164          destroy_trunk(trunk);
06165          return -1;
06166       }
06167    }
06168 
06169    AST_RWLIST_WRLOCK(&sla_trunks);
06170    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
06171    AST_RWLIST_UNLOCK(&sla_trunks);
06172 
06173    return 0;
06174 }

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

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

Referenced by sla_process_timers().

05343 {
05344    struct sla_station *station;
05345    int res = 0;
05346 
05347    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05348       struct sla_ringing_trunk *ringing_trunk;
05349       int time_left;
05350 
05351       /* Ignore stations already ringing */
05352       if (sla_check_ringing_station(station))
05353          continue;
05354 
05355       /* Ignore stations already on a call */
05356       if (sla_check_inuse_station(station))
05357          continue;
05358 
05359       /* Ignore stations that don't have one of their trunks ringing */
05360       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
05361          continue;
05362 
05363       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
05364          continue;
05365 
05366       /* If there is no time left, then the station needs to start ringing.
05367        * Return non-zero so that an event will be queued up an event to 
05368        * make that happen. */
05369       if (time_left <= 0) {
05370          res = 1;
05371          continue;
05372       }
05373 
05374       if (time_left < *timeout)
05375          *timeout = time_left;
05376    }
05377 
05378    return res;
05379 }

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

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

Referenced by sla_process_timers().

05260 {
05261    struct sla_ringing_trunk *ringing_trunk;
05262    struct sla_ringing_station *ringing_station;
05263    int res = 0;
05264 
05265    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05266       unsigned int ring_timeout = 0;
05267       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
05268       struct sla_trunk_ref *trunk_ref;
05269 
05270       /* If there are any ring timeouts specified for a specific trunk
05271        * on the station, then use the highest per-trunk ring timeout.
05272        * Otherwise, use the ring timeout set for the entire station. */
05273       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05274          struct sla_station_ref *station_ref;
05275          int trunk_time_elapsed, trunk_time_left;
05276 
05277          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05278             if (ringing_trunk->trunk == trunk_ref->trunk)
05279                break;
05280          }
05281          if (!ringing_trunk)
05282             continue;
05283 
05284          /* If there is a trunk that is ringing without a timeout, then the
05285           * only timeout that could matter is a global station ring timeout. */
05286          if (!trunk_ref->ring_timeout)
05287             break;
05288 
05289          /* This trunk on this station is ringing and has a timeout.
05290           * However, make sure this trunk isn't still ringing from a
05291           * previous timeout.  If so, don't consider it. */
05292          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
05293             if (station_ref->station == ringing_station->station)
05294                break;
05295          }
05296          if (station_ref)
05297             continue;
05298 
05299          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05300          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
05301          if (trunk_time_left > final_trunk_time_left)
05302             final_trunk_time_left = trunk_time_left;
05303       }
05304 
05305       /* No timeout was found for ringing trunks, and no timeout for the entire station */
05306       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
05307          continue;
05308 
05309       /* Compute how much time is left for a global station timeout */
05310       if (ringing_station->station->ring_timeout) {
05311          ring_timeout = ringing_station->station->ring_timeout;
05312          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
05313          time_left = (ring_timeout * 1000) - time_elapsed;
05314       }
05315 
05316       /* If the time left based on the per-trunk timeouts is smaller than the
05317        * global station ring timeout, use that. */
05318       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
05319          time_left = final_trunk_time_left;
05320 
05321       /* If there is no time left, the station needs to stop ringing */
05322       if (time_left <= 0) {
05323          AST_LIST_REMOVE_CURRENT(entry);
05324          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
05325          res = 1;
05326          continue;
05327       }
05328 
05329       /* There is still some time left for this station to ring, so save that
05330        * timeout if it is the first event scheduled to occur */
05331       if (time_left < *timeout)
05332          *timeout = time_left;
05333    }
05334    AST_LIST_TRAVERSE_SAFE_END;
05335 
05336    return res;
05337 }

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

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

Referenced by sla_process_timers().

05230 {
05231    struct sla_ringing_trunk *ringing_trunk;
05232    int res = 0;
05233 
05234    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05235       int time_left, time_elapsed;
05236       if (!ringing_trunk->trunk->ring_timeout)
05237          continue;
05238       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05239       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
05240       if (time_left <= 0) {
05241          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
05242          AST_LIST_REMOVE_CURRENT(entry);
05243          sla_stop_ringing_trunk(ringing_trunk);
05244          res = 1;
05245          continue;
05246       }
05247       if (time_left < *timeout)
05248          *timeout = time_left;
05249    }
05250    AST_LIST_TRAVERSE_SAFE_END;
05251 
05252    return res;
05253 }

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

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

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

04699 {
04700    struct sla_station *station;
04701    struct sla_trunk_ref *trunk_ref;
04702 
04703    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04704       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04705          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
04706             || trunk_ref == exclude)
04707             continue;
04708          trunk_ref->state = state;
04709          ast_devstate_changed(sla_state_to_devstate(state), 
04710             "SLA:%s_%s", station->name, trunk->name);
04711          break;
04712       }
04713    }
04714 }

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

Definition at line 6085 of file app_meetme.c.

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

Referenced by sla_build_trunk().

06086 {
06087    char *tech, *tech_data;
06088 
06089    tech_data = ast_strdupa(device);
06090    tech = strsep(&tech_data, "/");
06091 
06092    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
06093       return -1;
06094 
06095    return 0;
06096 }

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

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

Referenced by sla_ring_stations().

04978 {
04979    struct sla_failed_station *failed_station;
04980    int res = 0;
04981 
04982    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
04983       if (station != failed_station->station)
04984          continue;
04985       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
04986          AST_LIST_REMOVE_CURRENT(entry);
04987          ast_free(failed_station);
04988          break;
04989       }
04990       res = 1;
04991    }
04992    AST_LIST_TRAVERSE_SAFE_END
04993 
04994    return res;
04995 }

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

Check to see if a station is in use.

Definition at line 5063 of file app_meetme.c.

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

Referenced by sla_calc_station_delays(), and sla_ring_stations().

05064 {
05065    struct sla_trunk_ref *trunk_ref;
05066 
05067    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05068       if (trunk_ref->chan)
05069          return 1;
05070    }
05071 
05072    return 0;
05073 }

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

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

Referenced by sla_thread().

05422 {
05423    struct sla_station *station;
05424    struct sla_trunk *trunk;
05425 
05426    ast_mutex_lock(&sla.lock);
05427 
05428    if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks) 
05429       || !AST_LIST_EMPTY(&sla.ringing_stations)) {
05430       ast_mutex_unlock(&sla.lock);
05431       return;
05432    }
05433 
05434    AST_RWLIST_RDLOCK(&sla_stations);
05435    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
05436       if (station->ref_count)
05437          break;
05438    }
05439    AST_RWLIST_UNLOCK(&sla_stations);
05440    if (station) {
05441       ast_mutex_unlock(&sla.lock);
05442       return;
05443    }
05444 
05445    AST_RWLIST_RDLOCK(&sla_trunks);
05446    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05447       if (trunk->ref_count)
05448          break;
05449    }
05450    AST_RWLIST_UNLOCK(&sla_trunks);
05451    if (trunk) {
05452       ast_mutex_unlock(&sla.lock);
05453       return;
05454    }
05455 
05456    /* yay */
05457    sla_load_config(1);
05458    sla.reload = 0;
05459 
05460    ast_mutex_unlock(&sla.lock);
05461 }

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

References AST_LIST_TRAVERSE, sla, and sla_ringing_station::station.

Referenced by sla_calc_station_delays(), and sla_ring_stations().

04963 {
04964    struct sla_ringing_station *ringing_station;
04965 
04966    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
04967       if (station == ringing_station->station)
04968          return 1;
04969    }
04970 
04971    return 0;
04972 }

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

05095 {
05096    struct sla_trunk_ref *trunk_ref;
05097    unsigned int delay = UINT_MAX;
05098    int time_left, time_elapsed;
05099 
05100    if (!ringing_trunk)
05101       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
05102    else
05103       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
05104 
05105    if (!ringing_trunk || !trunk_ref)
05106       return delay;
05107 
05108    /* If this station has a ring delay specific to the highest priority
05109     * ringing trunk, use that.  Otherwise, use the ring delay specified
05110     * globally for the station. */
05111    delay = trunk_ref->ring_delay;
05112    if (!delay)
05113       delay = station->ring_delay;
05114    if (!delay)
05115       return INT_MAX;
05116 
05117    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05118    time_left = (delay * 1000) - time_elapsed;
05119 
05120    return time_left;
05121 }

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

Definition at line 4602 of file app_meetme.c.

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

Referenced by sla_find_trunk_ref_byname().

04604 {
04605    struct sla_station_ref *station_ref;
04606    struct sla_trunk_ref *trunk_ref;
04607 
04608    /* For each station that has this call on hold, check for private hold. */
04609    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
04610       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
04611          if (trunk_ref->trunk != trunk || station_ref->station == station)
04612             continue;
04613          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
04614             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
04615             return 1;
04616          return 0;
04617       }
04618    }
04619 
04620    return 0;
04621 }

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

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

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

04835 {
04836    struct sla_station_ref *timed_out_station;
04837 
04838    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
04839       if (station == timed_out_station->station)
04840          return 1;
04841    }
04842 
04843    return 0;
04844 }

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

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

Definition at line 5645 of file app_meetme.c.

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

Referenced by sla_station_exec().

05646 {
05647    struct sla_trunk_ref *trunk_ref = NULL;
05648 
05649    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05650       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
05651          break;
05652    }
05653 
05654    return trunk_ref;
05655 }

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

Choose the highest priority ringing trunk for a station.

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

Definition at line 4854 of file app_meetme.c.

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

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

04856 {
04857    struct sla_trunk_ref *s_trunk_ref;
04858    struct sla_ringing_trunk *ringing_trunk = NULL;
04859 
04860    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
04861       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04862          /* Make sure this is the trunk we're looking for */
04863          if (s_trunk_ref->trunk != ringing_trunk->trunk)
04864             continue;
04865 
04866          /* This trunk on the station is ringing.  But, make sure this station
04867           * didn't already time out while this trunk was ringing. */
04868          if (sla_check_timed_out_station(ringing_trunk, station))
04869             continue;
04870 
04871          if (rm)
04872             AST_LIST_REMOVE_CURRENT(entry);
04873 
04874          if (trunk_ref)
04875             *trunk_ref = s_trunk_ref;
04876 
04877          break;
04878       }
04879       AST_LIST_TRAVERSE_SAFE_END;
04880    
04881       if (ringing_trunk)
04882          break;
04883    }
04884 
04885    return ringing_trunk;
04886 }

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

Definition at line 4667 of file app_meetme.c.

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

Referenced by sla_ring_station().

04668 {
04669    struct sla_ringing_station *ringing_station;
04670 
04671    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
04672       return NULL;
04673 
04674    ringing_station->station = station;
04675    ringing_station->ring_begin = ast_tvnow();
04676 
04677    return ringing_station;
04678 }

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

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

04656 {
04657    struct sla_station_ref *station_ref;
04658 
04659    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
04660       return NULL;
04661 
04662    station_ref->station = station;
04663 
04664    return station_ref;
04665 }

static void sla_destroy ( void   )  [static]

Definition at line 6055 of file app_meetme.c.

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

Referenced by unload_module().

06056 {
06057    struct sla_trunk *trunk;
06058    struct sla_station *station;
06059 
06060    AST_RWLIST_WRLOCK(&sla_trunks);
06061    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
06062       destroy_trunk(trunk);
06063    AST_RWLIST_UNLOCK(&sla_trunks);
06064 
06065    AST_RWLIST_WRLOCK(&sla_stations);
06066    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
06067       destroy_station(station);
06068    AST_RWLIST_UNLOCK(&sla_stations);
06069 
06070    if (sla.thread != AST_PTHREADT_NULL) {
06071       ast_mutex_lock(&sla.lock);
06072       sla.stop = 1;
06073       ast_cond_signal(&sla.cond);
06074       ast_mutex_unlock(&sla.lock);
06075       pthread_join(sla.thread, NULL);
06076    }
06077 
06078    /* Drop any created contexts from the dialplan */
06079    ast_context_destroy(NULL, sla_registrar);
06080 
06081    ast_mutex_destroy(&sla.lock);
06082    ast_cond_destroy(&sla.cond);
06083 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 4825 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

04826 {
04827    sla_queue_event(SLA_EVENT_DIAL_STATE);
04828 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 4590 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, and sla_station::name.

Referenced by sla_station_exec().

04591 {
04592    struct sla_station *station = NULL;
04593 
04594    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
04595       if (!strcasecmp(station->name, name))
04596          break;
04597    }
04598 
04599    return station;
04600 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 4575 of file app_meetme.c.

References AST_RWLIST_TRAVERSE, and sla_trunk::name.

Referenced by sla_trunk_exec().

04576 {
04577    struct sla_trunk *trunk = NULL;
04578 
04579    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04580       if (!strcasecmp(trunk->name, name))
04581          break;
04582    }
04583 
04584    return trunk;
04585 }

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

Definition at line 5075 of file app_meetme.c.

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

Referenced by sla_check_station_delay().

05077 {
05078    struct sla_trunk_ref *trunk_ref = NULL;
05079 
05080    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05081       if (trunk_ref->trunk == trunk)
05082          break;
05083    }
05084 
05085    return trunk_ref;
05086 }

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

Find a trunk reference on a station by name.

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

Definition at line 4630 of file app_meetme.c.

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

Referenced by sla_station_exec().

04632 {
04633    struct sla_trunk_ref *trunk_ref = NULL;
04634 
04635    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04636       if (strcasecmp(trunk_ref->trunk->name, name))
04637          continue;
04638 
04639       if ( (trunk_ref->trunk->barge_disabled 
04640          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
04641          (trunk_ref->trunk->hold_stations 
04642          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
04643          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
04644          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
04645       {
04646          trunk_ref = NULL;
04647       }
04648 
04649       break;
04650    }
04651 
04652    return trunk_ref;
04653 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 4888 of file app_meetme.c.

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

Referenced by sla_thread().

04889 {
04890    struct sla_ringing_station *ringing_station;
04891 
04892    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04893       struct sla_trunk_ref *s_trunk_ref = NULL;
04894       struct sla_ringing_trunk *ringing_trunk = NULL;
04895       struct run_station_args args;
04896       enum ast_dial_result dial_res;
04897       pthread_t dont_care;
04898       ast_mutex_t cond_lock;
04899       ast_cond_t cond;
04900 
04901       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
04902       case AST_DIAL_RESULT_HANGUP:
04903       case AST_DIAL_RESULT_INVALID:
04904       case AST_DIAL_RESULT_FAILED:
04905       case AST_DIAL_RESULT_TIMEOUT:
04906       case AST_DIAL_RESULT_UNANSWERED:
04907          AST_LIST_REMOVE_CURRENT(entry);
04908          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
04909          break;
04910       case AST_DIAL_RESULT_ANSWERED:
04911          AST_LIST_REMOVE_CURRENT(entry);
04912          /* Find the appropriate trunk to answer. */
04913          ast_mutex_lock(&sla.lock);
04914          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
04915          ast_mutex_unlock(&sla.lock);
04916          if (!ringing_trunk) {
04917             ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
04918             break;
04919          }
04920          /* Track the channel that answered this trunk */
04921          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
04922          /* Actually answer the trunk */
04923          answer_trunk_chan(ringing_trunk->trunk->chan);
04924          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04925          /* Now, start a thread that will connect this station to the trunk.  The rest of
04926           * the code here sets up the thread and ensures that it is able to save the arguments
04927           * before they are no longer valid since they are allocated on the stack. */
04928          args.trunk_ref = s_trunk_ref;
04929          args.station = ringing_station->station;
04930          args.cond = &cond;
04931          args.cond_lock = &cond_lock;
04932          ast_free(ringing_trunk);
04933          ast_free(ringing_station);
04934          ast_mutex_init(&cond_lock);
04935          ast_cond_init(&cond, NULL);
04936          ast_mutex_lock(&cond_lock);
04937          ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
04938          ast_cond_wait(&cond, &cond_lock);
04939          ast_mutex_unlock(&cond_lock);
04940          ast_mutex_destroy(&cond_lock);
04941          ast_cond_destroy(&cond);
04942          break;
04943       case AST_DIAL_RESULT_TRYING:
04944       case AST_DIAL_RESULT_RINGING:
04945       case AST_DIAL_RESULT_PROGRESS:
04946       case AST_DIAL_RESULT_PROCEEDING:
04947          break;
04948       }
04949       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
04950          /* Queue up reprocessing ringing trunks, and then ringing stations again */
04951          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04952          sla_queue_event(SLA_EVENT_DIAL_STATE);
04953          break;
04954       }
04955    }
04956    AST_LIST_TRAVERSE_SAFE_END;
04957 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 5205 of file app_meetme.c.

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

Referenced by sla_thread().

05206 {
05207    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
05208    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
05209    ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", 
05210       event->station->name, event->trunk_ref->trunk->name);
05211    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
05212       INACTIVE_TRUNK_REFS, event->trunk_ref);
05213 
05214    if (event->trunk_ref->trunk->active_stations == 1) {
05215       /* The station putting it on hold is the only one on the call, so start
05216        * Music on hold to the trunk. */
05217       event->trunk_ref->trunk->on_hold = 1;
05218       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
05219    }
05220 
05221    ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
05222    event->trunk_ref->chan = NULL;
05223 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 5195 of file app_meetme.c.

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

Referenced by sla_thread().

05196 {
05197    ast_mutex_lock(&sla.lock);
05198    sla_ring_stations();
05199    ast_mutex_unlock(&sla.lock);
05200 
05201    /* Find stations that shouldn't be ringing anymore. */
05202    sla_hangup_stations();
05203 }

static void sla_hangup_stations ( void   )  [static]

Definition at line 5167 of file app_meetme.c.

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

Referenced by sla_handle_ringing_trunk_event().

05168 {
05169    struct sla_trunk_ref *trunk_ref;
05170    struct sla_ringing_station *ringing_station;
05171 
05172    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05173       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05174          struct sla_ringing_trunk *ringing_trunk;
05175          ast_mutex_lock(&sla.lock);
05176          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05177             if (trunk_ref->trunk == ringing_trunk->trunk)
05178                break;
05179          }
05180          ast_mutex_unlock(&sla.lock);
05181          if (ringing_trunk)
05182             break;
05183       }
05184       if (!trunk_ref) {
05185          AST_LIST_REMOVE_CURRENT(entry);
05186          ast_dial_join(ringing_station->station->dial);
05187          ast_dial_destroy(ringing_station->station->dial);
05188          ringing_station->station->dial = NULL;
05189          ast_free(ringing_station);
05190       }
05191    }
05192    AST_LIST_TRAVERSE_SAFE_END
05193 }

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

Definition at line 1525 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01526 {
01527    const char *hold = "Unknown";
01528 
01529    switch (hold_access) {
01530    case SLA_HOLD_OPEN:
01531       hold = "Open";
01532       break;
01533    case SLA_HOLD_PRIVATE:
01534       hold = "Private";
01535    default:
01536       break;
01537    }
01538 
01539    return hold;
01540 }

static int sla_load_config ( int  reload  )  [static]