Sat Aug 6 00:39:34 2011

Asterisk developer's documentation


app_meetme.c File Reference

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

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.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/options.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/astobj.h"
#include "asterisk/astobj2.h"
#include "asterisk/devicestate.h"
#include "asterisk/dial.h"
#include "asterisk/causes.h"
#include "asterisk/dahdi_compat.h"
#include "enter.h"
#include "leave.h"

Go to the source code of this file.

Data Structures

struct  announce_listitem
struct  ast_conf_user
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 DEFAULT_AUDIO_BUFFERS   32
#define MAX_CONFNUM   80
#define MAX_PIN   80
#define MAX_SETTINGS   (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)
#define MEETME_DELAYDETECTENDTALK   1000
#define MEETME_DELAYDETECTTALK   300
#define S(e)   case e: return # e;
#define SLA_CONFIG_FILE   "sla.conf"

Enumerations

enum  { ADMINFLAG_MUTED = (1 << 1), ADMINFLAG_SELFMUTED = (1 << 2), ADMINFLAG_KICKME = (1 << 3) }
enum  {
  CONFFLAG_ADMIN = (1 << 0), CONFFLAG_MONITOR = (1 << 1), CONFFLAG_POUNDEXIT = (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_NO_AUDIO_UNTIL_UP = (1 << 28), CONFFLAG_INTROMSG = (1 << 29)
}
enum  { OPT_ARG_WAITMARKED = 0, OPT_ARG_INTROMSG = 1, OPT_ARG_ARRAY_SIZE = 2 }
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 }
 Event types that can be queued up for the SLA thread. More...
enum  sla_hold_access { SLA_HOLD_OPEN, SLA_HOLD_PRIVATE }
enum  sla_station_hangup { SLA_STATION_HANGUP_NORMAL, SLA_STATION_HANGUP_TIMEOUT }
enum  sla_trunk_state {
  SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, SLA_TRUNK_STATE_ONHOLD,
  SLA_TRUNK_STATE_ONHOLD_BYME
}
enum  sla_which_trunk_refs { ALL_TRUNK_REFS, INACTIVE_TRUNK_REFS }
enum  volume_action { VOL_UP, VOL_DOWN }

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int action_meetmemute (struct mansession *s, const struct message *m)
static int action_meetmeunmute (struct mansession *s, const struct message *m)
static int admin_exec (struct ast_channel *chan, void *data)
 The MeetMeadmin application.
static void * announce_thread (void *data)
static void answer_trunk_chan (struct ast_channel *chan)
static struct ast_conferencebuild_conf (char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount)
 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 char * complete_meetmecmd (const char *line, const char *word, int pos, int state)
static int conf_exec (struct ast_channel *chan, void *data)
 The meetme() application.
static void conf_flush (int fd, struct ast_channel *chan)
static int conf_free (struct ast_conference *conf)
static void conf_play (struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
static void conf_queue_dtmf (const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
static int conf_run (struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
static int count_exec (struct ast_channel *chan, void *data)
 The MeetmeCount application.
static struct sla_trunk_refcreate_trunk_ref (struct sla_trunk *trunk)
static void destroy_station (struct sla_station *station)
static void destroy_trunk (struct sla_trunk *trunk)
static void * dial_trunk (void *data)
static int dispose_conf (struct ast_conference *conf)
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
static struct ast_conferencefind_conf_realtime (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
static struct ast_conf_userfind_user (struct ast_conference *conf, char *callerident)
static const char * get_announce_filename (enum announcetypes type)
static char * istalking (int x)
static int load_config (int reload)
static void load_config_meetme (void)
static int load_module (void)
static int meetme_cmd (int fd, int argc, char **argv)
static int meetmemute (struct mansession *s, const struct message *m, int mute)
static int meetmestate (const char *data)
 Callback for devicestate providers.
static struct sla_ringing_trunkqueue_ringing_trunk (struct sla_trunk *trunk)
static void * recordthread (void *args)
static int reload (void)
static void reset_volumes (struct ast_conf_user *user)
static void * run_station (void *data)
static void send_talking_event (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
static int set_listen_volume (struct ast_conf_user *user, int volume)
static int set_talk_volume (struct ast_conf_user *user, int volume)
static void set_user_talking (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
static void sla_add_trunk_to_station (struct sla_station *station, struct ast_variable *var)
static int sla_build_station (struct ast_config *cfg, const char *cat)
static int sla_build_trunk (struct ast_config *cfg, const char *cat)
static int sla_calc_station_delays (unsigned int *timeout)
 Calculate the ring delay for a station.
static int sla_calc_station_timeouts (unsigned int *timeout)
 Process station ring timeouts.
static int sla_calc_trunk_timeouts (unsigned int *timeout)
 Process trunk ring timeouts.
static void sla_change_trunk_state (const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
static int sla_check_device (const char *device)
static int sla_check_failed_station (const struct sla_station *station)
 Check to see if this station has failed to be dialed in the past minute.
static int sla_check_inuse_station (const struct sla_station *station)
 Check to see if a station is in use.
static int sla_check_ringing_station (const struct sla_station *station)
 Check to see if this station is already ringing.
static int sla_check_station_delay (struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
 Calculate the ring delay for a given ringing trunk on a station.
static int sla_check_station_hold_access (const struct sla_trunk *trunk, const struct sla_station *station)
static int sla_check_timed_out_station (const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
 Check to see if dialing this station already timed out for this ringing trunk.
static struct sla_trunk_refsla_choose_idle_trunk (const struct sla_station *station)
 For a given station, choose the highest priority idle trunk.
static struct sla_ringing_trunksla_choose_ringing_trunk (struct sla_station *station, struct sla_trunk_ref **trunk_ref, int remove)
 Choose the highest priority ringing trunk for a station.
static struct sla_ringing_stationsla_create_ringing_station (struct sla_station *station)
static struct sla_station_refsla_create_station_ref (struct sla_station *station)
static void sla_destroy (void)
static void sla_dial_state_callback (struct ast_dial *dial)
static struct sla_stationsla_find_station (const char *name)
 Find an SLA station by name.
static struct sla_trunksla_find_trunk (const char *name)
 Find an SLA trunk by name.
static struct sla_trunk_refsla_find_trunk_ref (const struct sla_station *station, const struct sla_trunk *trunk)
static struct sla_trunk_refsla_find_trunk_ref_byname (const struct sla_station *station, const char *name)
 Find a trunk reference on a station by name.
static void sla_handle_dial_state_event (void)
static void sla_handle_hold_event (struct sla_event *event)
static void sla_handle_ringing_trunk_event (void)
static void sla_hangup_stations (void)
static const char * sla_hold_str (unsigned int hold_access)
static int sla_load_config (void)
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 int sla_show_stations (int fd, int argc, char **argv)
static int sla_show_trunks (int fd, int argc, char **argv)
static int sla_state (const char *data)
static int sla_station_exec (struct ast_channel *chan, void *data)
static void sla_stop_ringing_station (struct sla_ringing_station *ringing_station, enum sla_station_hangup hangup)
static void sla_stop_ringing_trunk (struct sla_ringing_trunk *ringing_trunk)
static void * sla_thread (void *data)
static int sla_trunk_exec (struct ast_channel *chan, void *data)
static const char * trunkstate2str (enum sla_trunk_state state)
static void tweak_listen_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_talk_volume (struct ast_conf_user *user, enum volume_action action)
static void tweak_volume (struct volume *vol, enum volume_action action)
static int unload_module (void)
static int user_listen_voldown_cb (void *obj, void *unused, int flags)
static int user_listen_volup_cb (void *obj, void *unused, int flags)
static int user_max_cmp (void *obj, void *arg, int flags)
static int user_no_cmp (void *obj, void *arg, int flags)
static int user_reset_vol_cb (void *obj, void *unused, int flags)
static int user_set_kickme_cb (void *obj, void *unused, int flags)
static int user_set_muted_cb (void *obj, void *unused, int flags)
static int user_set_unmuted_cb (void *obj, void *unused, int flags)
static int user_talk_voldown_cb (void *obj, void *unused, int flags)
static int user_talk_volup_cb (void *obj, void *unused, int flags)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, }
static const char * app = "MeetMe"
static const char * app2 = "MeetMeCount"
static const char * app3 = "MeetMeAdmin"
static const struct ast_module_infoast_module_info = &__mod_info
static int audio_buffers
static struct ast_cli_entry cli_meetme []
static unsigned int conf_map [1024] = {0, }
static const char * descrip
static const char * descrip2
static const char * descrip3
static char const gain_map []
static struct ast_app_option meetme_opts [128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'G' ] = { .flag = CONFFLAG_INTROMSG , .arg_index = OPT_ARG_INTROMSG + 1 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_POUNDEXIT }, [ '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 }, }
static char meetme_usage []
struct {
   unsigned int   attempt_callerid:1
   ast_cond_t   cond
   struct {
      sla_event *   first
      sla_event *   last
   }   event_q
   struct {
      sla_failed_station *   first
      sla_failed_station *   last
   }   failed_stations
   ast_mutex_t   lock
   struct {
      sla_ringing_station *   first
      sla_ringing_station *   last
   }   ringing_stations
   struct {
      sla_ringing_trunk *   first
      sla_ringing_trunk *   last
   }   ringing_trunks
   unsigned int   stop:1
   pthread_t   thread
sla
 A structure for data used by the sla thread.
static const char sla_registrar [] = "SLA"
static const char sla_show_stations_usage []
static const char sla_show_trunks_usage []
static const char * slastation_app = "SLAStation"
static const char * slastation_desc
static const char * slastation_synopsis = "Shared Line Appearance Station"
static const char * slatrunk_app = "SLATrunk"
static const char * slatrunk_desc
static const char * slatrunk_synopsis = "Shared Line Appearance Trunk"
static const char * synopsis = "MeetMe conference bridge"
static const char * synopsis2 = "MeetMe participant count"
static const char * synopsis3 = "MeetMe conference Administration"


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

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

#define CONF_SIZE   320

Definition at line 111 of file app_meetme.c.

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 77 of file app_meetme.c.

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

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 81 of file app_meetme.c.

Referenced by load_config_meetme().

#define MAX_CONFNUM   80

Definition at line 325 of file app_meetme.c.

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

#define MAX_PIN   80

Definition at line 326 of file app_meetme.c.

Referenced by conf_exec().

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

Definition at line 329 of file app_meetme.c.

Referenced by conf_exec(), and find_conf().

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 90 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 89 of file app_meetme.c.

Referenced by conf_run().

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

Referenced by sms_readfile(), and trunkstate2str().

#define SLA_CONFIG_FILE   "sla.conf"

Definition at line 78 of file app_meetme.c.

Referenced by sla_load_config().


Enumeration Type Documentation

anonymous enum

Enumerator:
ADMINFLAG_MUTED  User is muted
ADMINFLAG_SELFMUTED  User muted self
ADMINFLAG_KICKME  User has been kicked

Definition at line 83 of file app_meetme.c.

00083      {
00084    ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
00085    ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
00086    ADMINFLAG_KICKME =    (1 << 3)  /*!< User has been kicked */
00087 };

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_POUNDEXIT  If set asterisk will exit conference when '#' 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, treats 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  This is a SLA station. (Only for use by the SLA applications.)
CONFFLAG_SLA_TRUNK  This is a SLA trunk. (Only for use by the SLA applications.)
CONFFLAG_NO_AUDIO_UNTIL_UP  Do not write any audio to this channel until the state is up.
CONFFLAG_INTROMSG  Play an arbitrary Intro message

Definition at line 113 of file app_meetme.c.

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

anonymous enum

Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_INTROMSG 
OPT_ARG_ARRAY_SIZE 

Definition at line 174 of file app_meetme.c.

00174      {
00175    OPT_ARG_WAITMARKED = 0,
00176    OPT_ARG_INTROMSG = 1,
00177    OPT_ARG_ARRAY_SIZE = 2,
00178 };

enum announcetypes

Enumerator:
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 331 of file app_meetme.c.

00331                    {
00332    CONF_HASJOIN,
00333    CONF_HASLEFT
00334 };

enum entrance_sound

Enumerator:
ENTER 
LEAVE 

Definition at line 99 of file app_meetme.c.

00099                     {
00100    ENTER,
00101    LEAVE
00102 };

enum recording_state

Enumerator:
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 104 of file app_meetme.c.

enum sla_event_type

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

Enumerator:
SLA_EVENT_HOLD  A station has put the call on hold
SLA_EVENT_DIAL_STATE  The state of a dial has changed
SLA_EVENT_RINGING_TRUNK  The state of a ringing trunk has changed

Definition at line 505 of file app_meetme.c.

00505                     {
00506    /*! A station has put the call on hold */
00507    SLA_EVENT_HOLD,
00508    /*! The state of a dial has changed */
00509    SLA_EVENT_DIAL_STATE,
00510    /*! The state of a ringing trunk has changed */
00511    SLA_EVENT_RINGING_TRUNK,
00512 };

enum sla_hold_access

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

Definition at line 419 of file app_meetme.c.

00419                      {
00420    /*! This means that any station can put it on hold, and any station
00421     * can retrieve the call from hold. */
00422    SLA_HOLD_OPEN,
00423    /*! This means that only the station that put the call on hold may
00424     * retrieve it from hold. */
00425    SLA_HOLD_PRIVATE,
00426 };

enum sla_station_hangup

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

Definition at line 538 of file app_meetme.c.

enum sla_trunk_state

Enumerator:
SLA_TRUNK_STATE_IDLE 
SLA_TRUNK_STATE_RINGING 
SLA_TRUNK_STATE_UP 
SLA_TRUNK_STATE_ONHOLD 
SLA_TRUNK_STATE_ONHOLD_BYME 

Definition at line 411 of file app_meetme.c.

enum sla_which_trunk_refs

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 406 of file app_meetme.c.

00406                           {
00407    ALL_TRUNK_REFS,
00408    INACTIVE_TRUNK_REFS,
00409 };

enum volume_action

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 94 of file app_meetme.c.

00094                    {
00095    VOL_UP,
00096    VOL_DOWN
00097 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 5204 of file app_meetme.c.

static void __unreg_module ( void   )  [static]

Definition at line 5204 of file app_meetme.c.

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

Definition at line 3317 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03318 {
03319    return meetmemute(s, m, 1);
03320 }

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

Definition at line 3322 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03323 {
03324    return meetmemute(s, m, 0);
03325 }

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

The MeetMeadmin application.

Definition at line 3123 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, ao2_callback(), ao2_find(), ao2_ref(), AST_APP_ARG, ast_atomic_fetchadd_int(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_module_user::chan, ast_conference::confno, dispose_conf(), find_user(), ast_conference::locked, LOG_NOTICE, LOG_WARNING, ast_conference::refcount, reset_volumes(), tweak_listen_volume(), tweak_talk_volume(), user_listen_voldown_cb(), user_listen_volup_cb(), user_max_cmp(), user_reset_vol_cb(), user_set_kickme_cb(), user_set_muted_cb(), user_set_unmuted_cb(), user_talk_voldown_cb(), user_talk_volup_cb(), ast_conference::usercontainer, ast_conf_user::userflags, and VOL_UP.

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

03123                                                             {
03124    char *params;
03125    struct ast_conference *cnf;
03126    struct ast_conf_user *user = NULL;
03127    struct ast_module_user *u;
03128    AST_DECLARE_APP_ARGS(args,
03129       AST_APP_ARG(confno);
03130       AST_APP_ARG(command);
03131       AST_APP_ARG(user);
03132    );
03133 
03134    if (ast_strlen_zero(data)) {
03135       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
03136       return -1;
03137    }
03138 
03139    u = ast_module_user_add(chan);
03140 
03141    AST_LIST_LOCK(&confs);
03142    
03143    params = ast_strdupa(data);
03144    AST_STANDARD_APP_ARGS(args, params);
03145 
03146    if (!args.command) {
03147       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
03148       AST_LIST_UNLOCK(&confs);
03149       ast_module_user_remove(u);
03150       return -1;
03151    }
03152    AST_LIST_TRAVERSE(&confs, cnf, list) {
03153       if (!strcmp(cnf->confno, args.confno))
03154          break;
03155    }
03156 
03157    if (!cnf) {
03158       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
03159       AST_LIST_UNLOCK(&confs);
03160       ast_module_user_remove(u);
03161       return 0;
03162    }
03163 
03164    ast_atomic_fetchadd_int(&cnf->refcount, 1);
03165 
03166    if (args.user) {
03167       user = find_user(cnf, args.user);
03168       if (!user) {
03169          ast_log(LOG_NOTICE, "Specified User not found!\n");
03170          goto usernotfound;
03171       }
03172    }
03173 
03174    switch (*args.command) {
03175    case 76: /* L: Lock */ 
03176       cnf->locked = 1;
03177       break;
03178    case 108: /* l: Unlock */ 
03179       cnf->locked = 0;
03180       break;
03181    case 75: /* K: kick all users */
03182       ao2_callback(cnf->usercontainer, 0, user_set_kickme_cb, NULL);
03183       break;
03184    case 101: /* e: Eject last user*/
03185    {
03186       int max_no = 0;
03187       ao2_callback(cnf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
03188       user = ao2_find(cnf->usercontainer, &max_no, 0);
03189       if (!(user->userflags & CONFFLAG_ADMIN))
03190          user->adminflags |= ADMINFLAG_KICKME;
03191       else
03192          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
03193       ao2_ref(user, -1);
03194       break;
03195    }
03196    case 77: /* M: Mute */ 
03197       user->adminflags |= ADMINFLAG_MUTED;
03198       break;
03199    case 78: /* N: Mute all (non-admin) users */
03200       ao2_callback(cnf->usercontainer, 0, user_set_muted_cb, NULL);
03201       break;               
03202    case 109: /* m: Unmute */ 
03203       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
03204       break;
03205    case 110: /* n: Unmute all users */
03206       ao2_callback(cnf->usercontainer, 0, user_set_unmuted_cb, NULL);
03207       break;
03208    case 107: /* k: Kick user */ 
03209       user->adminflags |= ADMINFLAG_KICKME;
03210       break;
03211    case 118: /* v: Lower all users listen volume */
03212       ao2_callback(cnf->usercontainer, 0, user_listen_voldown_cb, NULL);
03213       break;
03214    case 86: /* V: Raise all users listen volume */
03215       ao2_callback(cnf->usercontainer, 0, user_listen_volup_cb, NULL);
03216       break;
03217    case 115: /* s: Lower all users speaking volume */
03218       ao2_callback(cnf->usercontainer, 0, user_talk_voldown_cb, NULL);
03219       break;
03220    case 83: /* S: Raise all users speaking volume */
03221       ao2_callback(cnf->usercontainer, 0, user_talk_volup_cb, NULL);
03222       break;
03223    case 82: /* R: Reset all volume levels */
03224       ao2_callback(cnf->usercontainer, 0, user_reset_vol_cb, NULL);
03225       break;
03226    case 114: /* r: Reset user's volume level */
03227       reset_volumes(user);
03228       break;
03229    case 85: /* U: Raise user's listen volume */
03230       tweak_listen_volume(user, VOL_UP);
03231       break;
03232    case 117: /* u: Lower user's listen volume */
03233       tweak_listen_volume(user, VOL_DOWN);
03234       break;
03235    case 84: /* T: Raise user's talk volume */
03236       tweak_talk_volume(user, VOL_UP);
03237       break;
03238    case 116: /* t: Lower user's talk volume */
03239       tweak_talk_volume(user, VOL_DOWN);
03240       break;
03241    }
03242 
03243    if (args.user) {
03244       /* decrement reference from find_user */
03245       ao2_ref(user, -1);
03246    }
03247 usernotfound:
03248    AST_LIST_UNLOCK(&confs);
03249 
03250    dispose_conf(cnf);
03251 
03252    ast_module_user_remove(u);
03253    
03254    return 0;
03255 }

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

Definition at line 1495 of file app_meetme.c.

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

Referenced by conf_run().

01496 {
01497    struct announce_listitem *current;
01498    struct ast_conference *conf = data;
01499    int res;
01500    char filename[PATH_MAX] = "";
01501    AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
01502    AST_LIST_HEAD_INIT_NOLOCK(&local_list);
01503 
01504    while (!conf->announcethread_stop) {
01505       ast_mutex_lock(&conf->announcelistlock);
01506       if (conf->announcethread_stop) {
01507          ast_mutex_unlock(&conf->announcelistlock);
01508          break;
01509       }
01510       if (AST_LIST_EMPTY(&conf->announcelist))
01511          ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
01512 
01513       AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
01514       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01515 
01516       ast_mutex_unlock(&conf->announcelistlock);
01517       if (conf->announcethread_stop) {
01518          break;
01519       }
01520 
01521       for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
01522          ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
01523          if (!ast_fileexists(current->namerecloc, NULL, NULL))
01524             continue;
01525          if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
01526             if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
01527                res = ast_waitstream(current->confchan, "");
01528             if (!res) {
01529                ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
01530                if (!ast_streamfile(current->confchan, filename, current->language))
01531                   ast_waitstream(current->confchan, "");
01532             }
01533          }
01534          if (current->announcetype == CONF_HASLEFT) {
01535             ast_filedelete(current->namerecloc, NULL);
01536          }
01537       }
01538    }
01539 
01540    /* thread marked to stop, clean up */
01541    while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
01542       ast_filedelete(current->namerecloc, NULL);
01543       ao2_ref(current, -1);
01544    }
01545    return NULL;
01546 }

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

Definition at line 3573 of file app_meetme.c.

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

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

03574 {
03575    ast_answer(chan);
03576    ast_indicate(chan, -1);
03577 }

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

Find or create a conference.

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

Definition at line 798 of file app_meetme.c.

References ao2_container_alloc(), ao2_ref(), ast_atomic_fetchadd_int(), ast_calloc, ast_copy_string(), AST_FORMAT_SLINEAR, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_mutex_init(), AST_PTHREADT_NULL, ast_request(), ast_set_read_format(), ast_set_write_format(), ast_verbose(), conf_map, ast_conference::confno, dahdi_chan_name, DAHDI_FILE_PSEUDO, free, LOG_WARNING, option_verbose, user_no_cmp(), and VERBOSE_PREFIX_3.

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

00799 {
00800    struct ast_conference *cnf;
00801    struct dahdi_confinfo ztc = { 0, };
00802    int confno_int = 0;
00803 
00804    AST_LIST_LOCK(&confs);
00805 
00806    AST_LIST_TRAVERSE(&confs, cnf, list) {
00807       if (!strcmp(confno, cnf->confno)) 
00808          break;
00809    }
00810 
00811    if (cnf || (!make && !dynamic))
00812       goto cnfout;
00813 
00814    /* Make a new one */
00815    if (!(cnf = ast_calloc(1, sizeof(*cnf))) ||
00816       !(cnf->usercontainer = ao2_container_alloc(1, NULL, user_no_cmp))) {
00817       goto cnfout;
00818    }
00819 
00820    ast_mutex_init(&cnf->playlock);
00821    ast_mutex_init(&cnf->listenlock);
00822    cnf->recordthread = AST_PTHREADT_NULL;
00823    ast_mutex_init(&cnf->recordthreadlock);
00824    cnf->announcethread = AST_PTHREADT_NULL;
00825    ast_mutex_init(&cnf->announcethreadlock);
00826    ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00827    ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00828    ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00829 
00830    /* Setup a new zap conference */
00831    ztc.confno = -1;
00832    ztc.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00833    cnf->fd = open(DAHDI_FILE_PSEUDO, O_RDWR);
00834    if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &ztc)) {
00835       ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
00836       if (cnf->fd >= 0)
00837          close(cnf->fd);
00838       ao2_ref(cnf->usercontainer, -1);
00839       ast_mutex_destroy(&cnf->playlock);
00840       ast_mutex_destroy(&cnf->listenlock);
00841       ast_mutex_destroy(&cnf->recordthreadlock);
00842       ast_mutex_destroy(&cnf->announcethreadlock);
00843       free(cnf);
00844       cnf = NULL;
00845       goto cnfout;
00846    }
00847 
00848    cnf->zapconf = ztc.confno;
00849 
00850    /* Setup a new channel for playback of audio files */
00851    cnf->chan = ast_request(dahdi_chan_name, AST_FORMAT_SLINEAR, "pseudo", NULL);
00852    if (cnf->chan) {
00853       ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
00854       ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
00855       ztc.chan = 0;
00856       ztc.confno = cnf->zapconf;
00857       ztc.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00858       if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &ztc)) {
00859          ast_log(LOG_WARNING, "Error setting conference\n");
00860          if (cnf->chan)
00861             ast_hangup(cnf->chan);
00862          else
00863             close(cnf->fd);
00864          ao2_ref(cnf->usercontainer, -1);
00865          ast_mutex_destroy(&cnf->playlock);
00866          ast_mutex_destroy(&cnf->listenlock);
00867          ast_mutex_destroy(&cnf->recordthreadlock);
00868          ast_mutex_destroy(&cnf->announcethreadlock);
00869          free(cnf);
00870          cnf = NULL;
00871          goto cnfout;
00872       }
00873    }
00874 
00875    /* Fill the conference struct */
00876    cnf->start = time(NULL);
00877    cnf->isdynamic = dynamic ? 1 : 0;
00878    if (option_verbose > 2)
00879       ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
00880    AST_LIST_INSERT_HEAD(&confs, cnf, list);
00881 
00882    /* Reserve conference number in map */
00883    if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
00884       conf_map[confno_int] = 1;
00885    
00886 cnfout:
00887    if (cnf)
00888       ast_atomic_fetchadd_int(&cnf->refcount, refcount);
00889 
00890    AST_LIST_UNLOCK(&confs);
00891 
00892    return cnf;
00893 }

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

Definition at line 1548 of file app_meetme.c.

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

Referenced by conf_run().

01549 {
01550    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01551       return 1;
01552    }
01553 
01554    return (chan->_state == AST_STATE_UP);
01555 }

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

Definition at line 609 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

00610 {
00611    int res;
00612    int x;
00613 
00614    while (len) {
00615       if (block) {
00616          x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
00617          res = ioctl(fd, DAHDI_IOMUX, &x);
00618       } else
00619          res = 0;
00620       if (res >= 0)
00621          res = write(fd, data, len);
00622       if (res < 1) {
00623          if (errno != EAGAIN) {
00624             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00625             return -1;
00626          } else
00627             return 0;
00628       }
00629       len -= res;
00630       data += res;
00631    }
00632 
00633    return 0;
00634 }

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

Definition at line 1047 of file app_meetme.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ast_cli_complete(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_strdupa, ast_conference::confno, len(), ast_conf_user::list, strdup, ast_conf_user::user_no, and ast_conference::usercontainer.

01048 {
01049    static char *cmds[] = {"lock", "unlock", "mute", "unmute", "kick", "list", NULL};
01050 
01051    int len = strlen(word);
01052    int which = 0;
01053    struct ast_conference *cnf = NULL;
01054    struct ast_conf_user *usr = NULL;
01055    char *confno = NULL;
01056    char usrno[50] = "";
01057    char *myline, *ret = NULL;
01058    
01059    if (pos == 1) {      /* Command */
01060       return ast_cli_complete(word, cmds, state);
01061    } else if (pos == 2) {  /* Conference Number */
01062       AST_LIST_LOCK(&confs);
01063       AST_LIST_TRAVERSE(&confs, cnf, list) {
01064          if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
01065             ret = cnf->confno;
01066             break;
01067          }
01068       }
01069       ret = ast_strdup(ret); /* dup before releasing the lock */
01070       AST_LIST_UNLOCK(&confs);
01071       return ret;
01072    } else if (pos == 3) {
01073       /* User Number || Conf Command option*/
01074       if (strstr(line, "mute") || strstr(line, "kick")) {
01075          if (state == 0 && (strstr(line, "kick") || strstr(line,"mute")) && !strncasecmp(word, "all", len))
01076             return strdup("all");
01077          which++;
01078          AST_LIST_LOCK(&confs);
01079 
01080          /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
01081          myline = ast_strdupa(line);
01082          if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
01083             while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
01084                ;
01085          }
01086          
01087          AST_LIST_TRAVERSE(&confs, cnf, list) {
01088             if (!strcmp(confno, cnf->confno))
01089                 break;
01090          }
01091 
01092          if (cnf) {
01093             struct ao2_iterator user_iter;
01094             user_iter = ao2_iterator_init(cnf->usercontainer, 0);
01095             /* Search for the user */
01096             while((usr = ao2_iterator_next(&user_iter))) {
01097                snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
01098                if (!strncasecmp(word, usrno, len) && ++which > state) {
01099                   ao2_ref(usr, -1);
01100                   break;
01101                }
01102                ao2_ref(usr, -1);
01103             }
01104             ao2_iterator_destroy(&user_iter);
01105             AST_LIST_UNLOCK(&confs);
01106             return usr ? strdup(usrno) : NULL;
01107          }
01108          AST_LIST_UNLOCK(&confs);
01109       } else if ( strstr(line, "list") && ( 0 == state ) )
01110          return strdup("concise");
01111    }
01112 
01113    return NULL;
01114 }

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

The meetme() application.

Definition at line 2798 of file app_meetme.c.

References ast_channel::_state, 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_module_user_add, ast_module_user_remove, ast_say_digits(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_variable_browse(), ast_waitstream(), conf_map, conf_run(), CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFIG_FILE_NAME, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), ast_flags::flags, ast_conference::isdynamic, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, MAX_SETTINGS, meetme_opts, OPT_ARG_ARRAY_SIZE, parse(), ast_conference::pin, ast_conference::pinadmin, ast_conference::users, and var.

02799 {
02800    int res=-1;
02801    struct ast_module_user *u;
02802    char confno[MAX_CONFNUM] = "";
02803    int allowretry = 0;
02804    int retrycnt = 0;
02805    struct ast_conference *cnf = NULL;
02806    struct ast_flags confflags = {0};
02807    int dynamic = 0;
02808    int empty = 0, empty_no_pin = 0;
02809    int always_prompt = 0;
02810    char *notdata, *info, the_pin[MAX_PIN] = "";
02811    AST_DECLARE_APP_ARGS(args,
02812       AST_APP_ARG(confno);
02813       AST_APP_ARG(options);
02814       AST_APP_ARG(pin);
02815    );
02816    char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
02817 
02818    u = ast_module_user_add(chan);
02819 
02820    if (ast_strlen_zero(data)) {
02821       allowretry = 1;
02822       notdata = "";
02823    } else {
02824       notdata = data;
02825    }
02826    
02827    if (chan->_state != AST_STATE_UP)
02828       ast_answer(chan);
02829 
02830    info = ast_strdupa(notdata);
02831 
02832    AST_STANDARD_APP_ARGS(args, info);  
02833 
02834    if (args.confno) {
02835       ast_copy_string(confno, args.confno, sizeof(confno));
02836       if (ast_strlen_zero(confno)) {
02837          allowretry = 1;
02838       }
02839    }
02840    
02841    if (args.pin)
02842       ast_copy_string(the_pin, args.pin, sizeof(the_pin));
02843 
02844    if (args.options) {
02845       ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
02846       dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
02847       if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
02848          strcpy(the_pin, "q");
02849 
02850       empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
02851       empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
02852       always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
02853    }
02854 
02855    do {
02856       if (retrycnt > 3)
02857          allowretry = 0;
02858       if (empty) {
02859          int i;
02860          struct ast_config *cfg;
02861          struct ast_variable *var;
02862          int confno_int;
02863 
02864          /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
02865          if ((empty_no_pin) || (!dynamic)) {
02866             cfg = ast_config_load(CONFIG_FILE_NAME);
02867             if (cfg) {
02868                var = ast_variable_browse(cfg, "rooms");
02869                while (var) {
02870                   char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
02871                   if (!strcasecmp(var->name, "conf")) {
02872                      int found = 0;
02873                      ast_copy_string(parse, var->value, sizeof(parse));
02874                      confno_tmp = strsep(&stringp, "|,");
02875                      if (!dynamic) {
02876                         /* For static:  run through the list and see if this conference is empty */
02877                         AST_LIST_LOCK(&confs);
02878                         AST_LIST_TRAVERSE(&confs, cnf, list) {
02879                            if (!strcmp(confno_tmp, cnf->confno)) {
02880                               /* The conference exists, therefore it's not empty */
02881                               found = 1;
02882                               break;
02883                            }
02884                         }
02885                         AST_LIST_UNLOCK(&confs);
02886                         if (!found) {
02887                            /* At this point, we have a confno_tmp (static conference) that is empty */
02888                            if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
02889                               /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
02890                                * Case 2:  empty_no_pin and pin is blank (but not NULL)
02891                                * Case 3:  not empty_no_pin
02892                                */
02893                               ast_copy_string(confno, confno_tmp, sizeof(confno));
02894                               break;
02895                               /* XXX the map is not complete (but we do have a confno) */
02896                            }
02897                         }
02898                      }
02899                   }
02900                   var = var->next;
02901                }
02902                ast_config_destroy(cfg);
02903             }
02904          }
02905 
02906          /* Select first conference number not in use */
02907          if (ast_strlen_zero(confno) && dynamic) {
02908             AST_LIST_LOCK(&confs);
02909             for (i = 0; i < sizeof(conf_map) / sizeof(conf_map[0]); i++) {
02910                if (!conf_map[i]) {
02911                   snprintf(confno, sizeof(confno), "%d", i);
02912                   conf_map[i] = 1;
02913                   break;
02914                }
02915             }
02916             AST_LIST_UNLOCK(&confs);
02917          }
02918 
02919          /* Not found? */
02920          if (ast_strlen_zero(confno)) {
02921             res = ast_streamfile(chan, "conf-noempty", chan->language);
02922             if (!res)
02923                ast_waitstream(chan, "");
02924          } else {
02925             if (sscanf(confno, "%30d", &confno_int) == 1) {
02926                res = ast_streamfile(chan, "conf-enteringno", chan->language);
02927                if (!res) {
02928                   ast_waitstream(chan, "");
02929                   res = ast_say_digits(chan, confno_int, "", chan->language);
02930                }
02931             } else {
02932                ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
02933             }
02934          }
02935       }
02936 
02937       while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
02938          /* Prompt user for conference number */
02939          res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
02940          if (res < 0) {
02941             /* Don't try to validate when we catch an error */
02942             confno[0] = '\0';
02943             allowretry = 0;
02944             break;
02945          }
02946       }
02947       if (!ast_strlen_zero(confno)) {
02948          /* Check the validity of the conference */
02949          cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
02950             sizeof(the_pin), 1, &confflags);
02951          if (!cnf) {
02952             cnf = find_conf_realtime(chan, confno, 1, dynamic, 
02953                the_pin, sizeof(the_pin), 1, &confflags);
02954          }
02955 
02956          if (!cnf) {
02957             res = ast_streamfile(chan, "conf-invalid", chan->language);
02958             if (!res)
02959                ast_waitstream(chan, "");
02960             res = -1;
02961             if (allowretry)
02962                confno[0] = '\0';
02963          } else {
02964             if (((!ast_strlen_zero(cnf->pin)       &&
02965                !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
02966                  (!ast_strlen_zero(cnf->pinadmin)  &&
02967                    ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
02968                     (!ast_strlen_zero(cnf->pin) &&
02969                       ast_strlen_zero(cnf->pinadmin) &&
02970                       ast_test_flag(&confflags, CONFFLAG_ADMIN))) &&
02971                 (!(cnf->users == 0 && cnf->isdynamic))) {
02972                char pin[MAX_PIN] = "";
02973                int j;
02974 
02975                /* Allow the pin to be retried up to 3 times */
02976                for (j = 0; j < 3; j++) {
02977                   if (*the_pin && (always_prompt == 0)) {
02978                      ast_copy_string(pin, the_pin, sizeof(pin));
02979                      res = 0;
02980                   } else {
02981                      /* Prompt user for pin if pin is required */
02982                      res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
02983                   }
02984                   if (res >= 0) {
02985                      if ((!strcasecmp(pin, cnf->pin) &&
02986                           (ast_strlen_zero(cnf->pinadmin) ||
02987                            !ast_test_flag(&confflags, CONFFLAG_ADMIN))) ||
02988                           (!ast_strlen_zero(cnf->pinadmin) &&
02989                            !strcasecmp(pin, cnf->pinadmin))) {
02990                         /* Pin correct */
02991                         allowretry = 0;
02992                         if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
02993                            ast_set_flag(&confflags, CONFFLAG_ADMIN);
02994                         /* Run the conference */
02995                         res = conf_run(chan, cnf, confflags.flags, optargs);
02996                         break;
02997                      } else {
02998                         /* Pin invalid */
02999                         if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
03000                            res = ast_waitstream(chan, AST_DIGIT_ANY);
03001                            ast_stopstream(chan);
03002                         }
03003                         else {
03004                            ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
03005                            break;
03006                         }
03007                         if (res < 0)
03008                            break;
03009                         pin[0] = res;
03010                         pin[1] = '\0';
03011                         res = -1;
03012                         if (allowretry)
03013                            confno[0] = '\0';
03014                      }
03015                   } else {
03016                      /* failed when getting the pin */
03017                      res = -1;
03018                      allowretry = 0;
03019                      /* see if we need to get rid of the conference */
03020                      break;
03021                   }
03022 
03023                   /* Don't retry pin with a static pin */
03024                   if (*the_pin && (always_prompt==0)) {
03025                      break;
03026                   }
03027                }
03028             } else {
03029                /* No pin required */
03030                allowretry = 0;
03031 
03032                /* Run the conference */
03033                res = conf_run(chan, cnf, confflags.flags, optargs);
03034             }
03035             dispose_conf(cnf);
03036             cnf = NULL;
03037          }
03038       }
03039    } while (allowretry);
03040 
03041    if (cnf)
03042       dispose_conf(cnf);
03043 
03044    ast_module_user_remove(u);
03045    
03046    return res;
03047 }

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

Definition at line 1280 of file app_meetme.c.

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

Referenced by conf_run().

01281 {
01282    int x;
01283 
01284    /* read any frames that may be waiting on the channel
01285       and throw them away
01286    */
01287    if (chan) {
01288       struct ast_frame *f;
01289 
01290       /* when no frames are available, this will wait
01291          for 1 millisecond maximum
01292       */
01293       while (ast_waitfor(chan, 1)) {
01294          f = ast_read(chan);
01295          if (f)
01296             ast_frfree(f);
01297          else /* channel was hung up or something else happened */
01298             break;
01299       }
01300    }
01301 
01302    /* flush any data sitting in the pseudo channel */
01303    x = DAHDI_FLUSH_ALL;
01304    if (ioctl(fd, DAHDI_FLUSH, &x))
01305       ast_log(LOG_WARNING, "Error flushing channel\n");
01306 
01307 }

static int conf_free ( struct ast_conference conf  )  [static]

Definition at line 1311 of file app_meetme.c.

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

Referenced by dispose_conf().

01312 {
01313    int x;
01314    struct announce_listitem *item;
01315    
01316    AST_LIST_REMOVE(&confs, conf, list);
01317 
01318    if (conf->recording == MEETME_RECORD_ACTIVE) {
01319       conf->recording = MEETME_RECORD_TERMINATE;
01320       AST_LIST_UNLOCK(&confs);
01321       while (1) {
01322          usleep(1);
01323          AST_LIST_LOCK(&confs);
01324          if (conf->recording == MEETME_RECORD_OFF)
01325             break;
01326          AST_LIST_UNLOCK(&confs);
01327       }
01328    }
01329 
01330    for (x=0;x<AST_FRAME_BITS;x++) {
01331       if (conf->transframe[x])
01332          ast_frfree(conf->transframe[x]);
01333       if (conf->transpath[x])
01334          ast_translator_free_path(conf->transpath[x]);
01335    }
01336    if (conf->announcethread != AST_PTHREADT_NULL) {
01337       ast_mutex_lock(&conf->announcelistlock);
01338       conf->announcethread_stop = 1;
01339       ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01340       ast_cond_signal(&conf->announcelist_addition);
01341       ast_mutex_unlock(&conf->announcelistlock);
01342       pthread_join(conf->announcethread, NULL);
01343    
01344       while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01345          ast_filedelete(item->namerecloc, NULL);
01346          ao2_ref(item, -1);
01347       }
01348       ast_mutex_destroy(&conf->announcelistlock);
01349    }
01350    if (conf->origframe)
01351       ast_frfree(conf->origframe);
01352    if (conf->lchan)
01353       ast_hangup(conf->lchan);
01354    if (conf->chan)
01355       ast_hangup(conf->chan);
01356    if (conf->fd >= 0)
01357       close(conf->fd);
01358    if (conf->usercontainer) {
01359       ao2_ref(conf->usercontainer, -1);
01360    }
01361 
01362    ast_mutex_destroy(&conf->playlock);
01363    ast_mutex_destroy(&conf->listenlock);
01364    ast_mutex_destroy(&conf->recordthreadlock);
01365    ast_mutex_destroy(&conf->announcethreadlock);
01366 
01367    free(conf);
01368 
01369    return 0;
01370 }

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

Definition at line 727 of file app_meetme.c.

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

Referenced by conf_run().

00728 {
00729    unsigned char *data;
00730    int len;
00731    int res = -1;
00732 
00733    if (!chan->_softhangup)
00734       res = ast_autoservice_start(chan);
00735 
00736    AST_LIST_LOCK(&confs);
00737 
00738    switch(sound) {
00739    case ENTER:
00740       data = enter;
00741       len = sizeof(enter);
00742       break;
00743    case LEAVE:
00744       data = leave;
00745       len = sizeof(leave);
00746       break;
00747    default:
00748       data = NULL;
00749       len = 0;
00750    }
00751    if (data) {
00752       careful_write(conf->fd, data, len, 1);
00753    }
00754 
00755    AST_LIST_UNLOCK(&confs);
00756 
00757    if (!res) 
00758       ast_autoservice_stop(chan);
00759 }

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

Definition at line 1372 of file app_meetme.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ast_log(), ast_write(), ast_conf_user::chan, f, LOG_WARNING, ast_channel::name, and ast_conference::usercontainer.

Referenced by conf_run().

01374 {
01375    struct ast_conf_user *user;
01376    struct ao2_iterator user_iter;
01377 
01378    user_iter = ao2_iterator_init(conf->usercontainer, 0);
01379    while ((user = ao2_iterator_next(&user_iter))) {
01380       if (user == sender) {
01381          ao2_ref(user, -1);
01382          continue;
01383       }
01384       if (ast_write(user->chan, f) < 0)
01385          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01386       ao2_ref(user, -1);
01387    }
01388    ao2_iterator_destroy(&user_iter);
01389 }

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

Definition at line 1586 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, announce_thread(), ast_conference::announcelist, ast_conference::announcelist_addition, ast_conference::announcelistlock, ast_conference::announcethread, ast_conference::announcethreadlock, ao2_alloc(), ao2_callback(), ao2_find(), ao2_lock(), ao2_ref(), ao2_unlock(), app, ast_channel_setoption(), ast_check_hangup(), ast_cond_signal(), ast_config_AST_SPOOL_DIR, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, ast_copy_string(), ast_device_state_changed(), AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_new(), ast_dsp_silence(), ast_exists_extension(), 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_frfree, AST_FRIENDLY_OFFSET, ast_goto_if_exists(), ast_hangup(), ast_indicate(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_NEXT, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, 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_PTHREADT_NULL, ast_read(), ast_read_noaudio(), ast_record_review(), ast_request(), ast_safe_sleep(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_translate(), ast_translator_build_path(), ast_update_realtime(), ast_verbose(), ast_waitfor_nandfds(), ast_waitstream(), ast_write(), ast_conference::attr, audio_buffers, ast_channel::audiohooks, can_write(), careful_write(), ast_conf_user::chan, ast_conference::chan, conf_flush(), CONF_HASJOIN, conf_play(), conf_queue_dtmf(), CONF_SIZE, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROMSG, CONFFLAG_INTROUSER, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_POUNDEXIT, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_SLA_STATION, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, ast_channel::context, dahdi_chan_name, DAHDI_FILE_PSEUDO, ENTER, announce_listitem::entry, errno, EVENT_FLAG_CALL, exitcontext, f, ast_channel::fds, ast_frame::frametype, ast_channel::language, ast_conference::lchan, ast_conference::listenlock, ast_conference::locked, LOG_DEBUG, LOG_WARNING, ast_channel::macrocontext, manager_event(), ast_conference::markedusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, ast_channel::monitor, ast_channel::name, OPT_ARG_INTROMSG, OPT_ARG_WAITMARKED, option_debug, ast_conference::origframe, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), ast_conference::playlock, ast_channel::rawwriteformat, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::recordthread, ast_conference::recordthreadlock, s, set_talk_volume(), set_user_talking(), SLA_EVENT_HOLD, sla_queue_event_conf(), ast_channel::tech, ast_conference::transframe, ast_conference::transpath, tweak_listen_volume(), tweak_talk_volume(), ast_channel_tech::type, ast_channel::uniqueid, user_max_cmp(), ast_conference::usercontainer, ast_conf_user::userflags, ast_conference::users, VERBOSE_PREFIX_4, VOL_UP, and ast_conference::zapconf.

01587 {
01588    struct ast_conf_user *user = NULL;
01589    int fd;
01590    struct dahdi_confinfo ztc, ztc_empty;
01591    struct ast_frame *f;
01592    struct ast_channel *c;
01593    struct ast_frame fr;
01594    int outfd;
01595    int ms;
01596    int nfds;
01597    int res;
01598    int retryzap;
01599    int origfd;
01600    int musiconhold = 0, mohtempstopped = 0;
01601    int firstpass = 0;
01602    int lastmarked = 0;
01603    int currentmarked = 0;
01604    int ret = -1;
01605    int x;
01606    int menu_active = 0;
01607    int using_pseudo = 0;
01608    int duration=20;
01609    int hr, min, sec;
01610    int sent_event = 0;
01611    time_t now;
01612    struct ast_dsp *dsp=NULL;
01613    struct ast_app *app;
01614    const char *agifile;
01615    const char *agifiledefault = "conf-background.agi";
01616    char meetmesecs[30] = "";
01617    char exitcontext[AST_MAX_CONTEXT] = "";
01618    char recordingtmp[AST_MAX_EXTENSION] = "";
01619    char members[10] = "";
01620    int dtmf, opt_waitmarked_timeout = 0;
01621    time_t timeout = 0;
01622    struct dahdi_bufferinfo bi;
01623    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
01624    char *buf = __buf + AST_FRIENDLY_OFFSET;
01625    int setusercount = 0;
01626    int confsilence = 0, totalsilence = 0;
01627 
01628    if (!(user = ao2_alloc(sizeof(*user), NULL))) {
01629       return ret;
01630    }
01631 
01632    /* Possible timeout waiting for marked user */
01633    if ((confflags & CONFFLAG_WAITMARKED) &&
01634       !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
01635       (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
01636       (opt_waitmarked_timeout > 0)) {
01637       timeout = time(NULL) + opt_waitmarked_timeout;
01638    }
01639 
01640    if (confflags & CONFFLAG_RECORDCONF) {
01641       if (!conf->recordingfilename) {
01642          conf->recordingfilename = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE");
01643          if (!conf->recordingfilename) {
01644             snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
01645             conf->recordingfilename = ast_strdupa(recordingtmp);
01646          }
01647          conf->recordingformat = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT");
01648          if (!conf->recordingformat) {
01649             snprintf(recordingtmp, sizeof(recordingtmp), "wav");
01650             conf->recordingformat = ast_strdupa(recordingtmp);
01651          }
01652          ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n",
01653                 conf->confno, conf->recordingfilename, conf->recordingformat);
01654       }
01655    }
01656 
01657    ast_mutex_lock(&conf->recordthreadlock);
01658    if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request(dahdi_chan_name, AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
01659       ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
01660       ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
01661       ztc.chan = 0;
01662       ztc.confno = conf->zapconf;
01663       ztc.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01664       if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &ztc)) {
01665          ast_log(LOG_WARNING, "Error starting listen channel\n");
01666          ast_hangup(conf->lchan);
01667          conf->lchan = NULL;
01668       } else {
01669          pthread_attr_init(&conf->attr);
01670          pthread_attr_setdetachstate(&conf->attr, PTHREAD_CREATE_DETACHED);
01671          ast_pthread_create_background(&conf->recordthread, &conf->attr, recordthread, conf);
01672          pthread_attr_destroy(&conf->attr);
01673       }
01674    }
01675    ast_mutex_unlock(&conf->recordthreadlock);
01676 
01677    ast_mutex_lock(&conf->announcethreadlock);
01678    if ((conf->announcethread == AST_PTHREADT_NULL) && !(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
01679       ast_mutex_init(&conf->announcelistlock);
01680       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01681       ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
01682    }
01683    ast_mutex_unlock(&conf->announcethreadlock);
01684 
01685    time(&user->jointime);
01686 
01687    if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
01688       /* Sorry, but this confernce is locked! */   
01689       if (!ast_streamfile(chan, "conf-locked", chan->language))
01690          ast_waitstream(chan, "");
01691       goto outrun;
01692    }
01693 
01694       ast_mutex_lock(&conf->playlock);
01695    ao2_lock(conf->usercontainer);
01696    ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &user->user_no);
01697    user->user_no++;
01698    ao2_link(conf->usercontainer, user);
01699    ao2_unlock(conf->usercontainer);
01700 
01701    user->chan = chan;
01702    user->userflags = confflags;
01703    user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
01704    user->talking = -1;
01705 
01706    ast_mutex_unlock(&conf->playlock);
01707 
01708    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
01709       char destdir[PATH_MAX];
01710 
01711       snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
01712 
01713       if (mkdir(destdir, 0777) && errno != EEXIST) {
01714          ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
01715          goto outrun;
01716       }
01717 
01718       snprintf(user->namerecloc, sizeof(user->namerecloc),
01719           "%s/meetme-username-%s-%d", destdir,
01720           conf->confno, user->user_no);
01721       if (confflags & CONFFLAG_INTROUSERNOREVIEW)
01722          res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, 128, 0, NULL);
01723       else
01724          res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
01725       if (res == -1)
01726          goto outrun;
01727    }
01728 
01729    ast_mutex_lock(&conf->playlock);
01730 
01731    if (confflags & CONFFLAG_MARKEDUSER)
01732       conf->markedusers++;
01733    conf->users++;
01734    /* Update table */
01735    snprintf(members, sizeof(members), "%d", conf->users);
01736    ast_update_realtime("meetme", "confno", conf->confno, "members", members , NULL);
01737    setusercount = 1;
01738 
01739    /* This device changed state now - if this is the first user */
01740    if (conf->users == 1)
01741       ast_device_state_changed("meetme:%s", conf->confno);
01742 
01743    ast_mutex_unlock(&conf->playlock);
01744 
01745    if (confflags & CONFFLAG_EXIT_CONTEXT) {
01746       if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) 
01747          ast_copy_string(exitcontext, agifile, sizeof(exitcontext));
01748       else if (!ast_strlen_zero(chan->macrocontext)) 
01749          ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
01750       else
01751          ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
01752    }
01753 
01754    /* Playback artbitrary intro message */
01755    if ((confflags & CONFFLAG_INTROMSG) &&
01756       !ast_strlen_zero(optargs[OPT_ARG_INTROMSG])) {
01757       if (!ast_streamfile(chan, optargs[OPT_ARG_INTROMSG], chan->language))
01758          ast_waitstream(chan, "");
01759    }
01760 
01761    if ( !(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON)) ) {
01762       if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
01763          if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
01764             ast_waitstream(chan, "");
01765       if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
01766          if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
01767             ast_waitstream(chan, "");
01768    }
01769 
01770    if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
01771       int keepplaying = 1;
01772 
01773       if (conf->users == 2) { 
01774          if (!ast_streamfile(chan,"conf-onlyone",chan->language)) {
01775             res = ast_waitstream(chan, AST_DIGIT_ANY);
01776             ast_stopstream(chan);
01777             if (res > 0)
01778                keepplaying=0;
01779             else if (res == -1)
01780                goto outrun;
01781          }
01782       } else { 
01783          if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
01784             res = ast_waitstream(chan, AST_DIGIT_ANY);
01785             ast_stopstream(chan);
01786             if (res > 0)
01787                keepplaying=0;
01788             else if (res == -1)
01789                goto outrun;
01790          }
01791          if (keepplaying) {
01792             res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
01793             if (res > 0)
01794                keepplaying=0;
01795             else if (res == -1)
01796                goto outrun;
01797          }
01798          if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
01799             res = ast_waitstream(chan, AST_DIGIT_ANY);
01800             ast_stopstream(chan);
01801             if (res > 0)
01802                keepplaying=0;
01803             else if (res == -1) 
01804                goto outrun;
01805          }
01806       }
01807    }
01808 
01809    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01810       /* We're leaving this alone until the state gets changed to up */
01811       ast_indicate(chan, -1);
01812    }
01813 
01814    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
01815       ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
01816       goto outrun;
01817    }
01818 
01819    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
01820       ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
01821       goto outrun;
01822    }
01823 
01824    retryzap = (strcasecmp(chan->tech->type, dahdi_chan_name) || (chan->audiohooks || chan->monitor) ? 1 : 0);
01825    user->zapchannel = !retryzap;
01826 
01827  zapretry:
01828    origfd = chan->fds[0];
01829    if (retryzap) {
01830       /* open pseudo in non-blocking mode */
01831       fd = open(DAHDI_FILE_PSEUDO, O_RDWR | O_NONBLOCK);
01832       if (fd < 0) {
01833          ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
01834          goto outrun;
01835       }
01836       using_pseudo = 1;
01837       /* Setup buffering information */
01838       memset(&bi, 0, sizeof(bi));
01839       bi.bufsize = CONF_SIZE/2;
01840       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
01841       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
01842       bi.numbufs = audio_buffers;
01843       if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
01844          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
01845          close(fd);
01846          goto outrun;
01847       }
01848       x = 1;
01849       if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
01850          ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
01851          close(fd);
01852          goto outrun;
01853       }
01854       nfds = 1;
01855    } else {
01856       /* XXX Make sure we're not running on a pseudo channel XXX */
01857       fd = chan->fds[0];
01858       nfds = 0;
01859    }
01860    memset(&ztc, 0, sizeof(ztc));
01861    memset(&ztc_empty, 0, sizeof(ztc_empty));
01862    /* Check to see if we're in a conference... */
01863    ztc.chan = 0;  
01864    if (ioctl(fd, DAHDI_GETCONF, &ztc)) {
01865       ast_log(LOG_WARNING, "Error getting conference\n");
01866       close(fd);
01867       goto outrun;
01868    }
01869    if (ztc.confmode) {
01870       /* Whoa, already in a conference...  Retry... */
01871       if (!retryzap) {
01872          ast_log(LOG_DEBUG, "%s channel is in a conference already, retrying with pseudo\n", dahdi_chan_name);
01873          retryzap = 1;
01874          goto zapretry;
01875       }
01876    }
01877    memset(&ztc, 0, sizeof(ztc));
01878    /* Add us to the conference */
01879    ztc.chan = 0;  
01880    ztc.confno = conf->zapconf;
01881 
01882    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
01883       struct announce_listitem *item;
01884       if (!(item = ao2_alloc(sizeof(*item), NULL)))
01885          goto outrun;
01886       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
01887       ast_copy_string(item->language, chan->language, sizeof(item->language));
01888       item->confchan = conf->chan;
01889       item->confusers = conf->users;
01890       item->announcetype = CONF_HASJOIN;
01891       ast_mutex_lock(&conf->announcelistlock);
01892       ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
01893       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
01894       ast_cond_signal(&conf->announcelist_addition);
01895       ast_mutex_unlock(&conf->announcelistlock);
01896 
01897       while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
01898          ;
01899       }
01900       ao2_ref(item, -1);
01901    }
01902 
01903    if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers)
01904       ztc.confmode = DAHDI_CONF_CONF;
01905    else if (confflags & CONFFLAG_MONITOR)
01906       ztc.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
01907    else if (confflags & CONFFLAG_TALKER)
01908       ztc.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
01909    else 
01910       ztc.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
01911 
01912    if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
01913       ast_log(LOG_WARNING, "Error setting conference\n");
01914       close(fd);
01915       goto outrun;
01916    }
01917    if (option_debug) {
01918       ast_log(LOG_DEBUG, "Placed channel %s in %s conf %d\n", chan->name, dahdi_chan_name, conf->zapconf);
01919    }
01920 
01921    if (!sent_event) {
01922       manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
01923                "Channel: %s\r\n"
01924                "Uniqueid: %s\r\n"
01925                "Meetme: %s\r\n"
01926                "Usernum: %d\r\n",
01927                chan->name, chan->uniqueid, conf->confno, user->user_no);
01928       sent_event = 1;
01929    }
01930 
01931    if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
01932       firstpass = 1;
01933       if (!(confflags & CONFFLAG_QUIET))
01934          if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
01935             conf_play(chan, conf, ENTER);
01936    }
01937 
01938    conf_flush(fd, chan);
01939 
01940    if (dsp)
01941       ast_dsp_free(dsp);
01942 
01943    if (!(dsp = ast_dsp_new())) {
01944       ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
01945       res = -1;
01946    }
01947 
01948    if (confflags & CONFFLAG_AGI) {
01949       /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
01950          or use default filename of conf-background.agi */
01951 
01952       agifile = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND");
01953       if (!agifile)
01954          agifile = agifiledefault;
01955 
01956       if (user->zapchannel) {
01957          /*  Set CONFMUTE mode on Zap channel to mute DTMF tones */
01958          x = 1;
01959          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01960       }
01961       /* Find a pointer to the agi app and execute the script */
01962       app = pbx_findapp("agi");
01963       if (app) {
01964          char *s = ast_strdupa(agifile);
01965          ret = pbx_exec(chan, app, s);
01966       } else {
01967          ast_log(LOG_WARNING, "Could not find application (agi)\n");
01968          ret = -2;
01969       }
01970       if (user->zapchannel) {
01971          /*  Remove CONFMUTE mode on Zap channel */
01972          x = 0;
01973          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01974       }
01975    } else {
01976       if (user->zapchannel && (confflags & CONFFLAG_STARMENU)) {
01977          /*  Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
01978          x = 1;
01979          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01980       }  
01981       for(;;) {
01982          int menu_was_active = 0;
01983 
01984          outfd = -1;
01985          ms = -1;
01986 
01987          if (timeout && time(NULL) >= timeout)
01988             break;
01989 
01990          /* if we have just exited from the menu, and the user had a channel-driver
01991             volume adjustment, restore it
01992          */
01993          if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
01994             set_talk_volume(user, user->listen.desired);
01995 
01996          menu_was_active = menu_active;
01997 
01998          currentmarked = conf->markedusers;
01999          if (!(confflags & CONFFLAG_QUIET) &&
02000              (confflags & CONFFLAG_MARKEDUSER) &&
02001              (confflags & CONFFLAG_WAITMARKED) &&
02002              lastmarked == 0) {
02003             if (currentmarked == 1 && conf->users > 1) {
02004                ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
02005                if (conf->users - 1 == 1) {
02006                   if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
02007                      ast_waitstream(chan, "");
02008                } else {
02009                   if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
02010                      ast_waitstream(chan, "");
02011                }
02012             }
02013             if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
02014                if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
02015                   ast_waitstream(chan, "");
02016          }
02017 
02018          /* Update the struct with the actual confflags */
02019          user->userflags = confflags;
02020 
02021          if (confflags & CONFFLAG_WAITMARKED) {
02022             if(currentmarked == 0) {
02023                if (lastmarked != 0) {
02024                   if (!(confflags & CONFFLAG_QUIET))
02025                      if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
02026                         ast_waitstream(chan, "");
02027                   if(confflags & CONFFLAG_MARKEDEXIT)
02028                      break;
02029                   else {
02030                      ztc.confmode = DAHDI_CONF_CONF;
02031                      if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
02032                         ast_log(LOG_WARNING, "Error setting conference\n");
02033                         close(fd);
02034                         goto outrun;
02035                      }
02036                   }
02037                }
02038                if (musiconhold == 0 && (confflags & CONFFLAG_MOH)) {
02039                   ast_moh_start(chan, NULL, NULL);
02040                   musiconhold = 1;
02041                }
02042             } else if(currentmarked >= 1 && lastmarked == 0) {
02043                /* Marked user entered, so cancel timeout */
02044                timeout = 0;
02045                if (confflags & CONFFLAG_MONITOR)
02046                   ztc.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02047                else if (confflags & CONFFLAG_TALKER)
02048                   ztc.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02049                else
02050                   ztc.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02051                if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
02052                   ast_log(LOG_WARNING, "Error setting conference\n");
02053                   close(fd);
02054                   goto outrun;
02055                }
02056                if (musiconhold && (confflags & CONFFLAG_MOH)) {
02057                   ast_moh_stop(chan);
02058                   musiconhold = 0;
02059                }
02060                if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
02061                   if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
02062                      ast_waitstream(chan, "");
02063                   conf_play(chan, conf, ENTER);
02064                }
02065             }
02066          }
02067 
02068          /* trying to add moh for single person conf */
02069          if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
02070             if (conf->users == 1) {
02071                if (musiconhold == 0) {
02072                   ast_moh_start(chan, NULL, NULL);
02073                   musiconhold = 1;
02074                } 
02075             } else {
02076                if (musiconhold) {
02077                   ast_moh_stop(chan);
02078                   musiconhold = 0;
02079                }
02080             }
02081          }
02082          
02083          /* Leave if the last marked user left */
02084          if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
02085             ret = -1;
02086             break;
02087          }
02088    
02089          /* Check if my modes have changed */
02090 
02091          /* If I should be muted but am still talker, mute me */
02092          if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (ztc.confmode & DAHDI_CONF_TALKER)) {
02093             ztc.confmode ^= DAHDI_CONF_TALKER;
02094             if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
02095                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02096                ret = -1;
02097                break;
02098             }
02099 
02100             /* Indicate user is not talking anymore - change him to unmonitored state */
02101             if ((confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) {
02102                set_user_talking(chan, conf, user, -1, confflags & CONFFLAG_MONITORTALKER);
02103             }
02104 
02105             manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
02106                   "Channel: %s\r\n"
02107                   "Uniqueid: %s\r\n"
02108                   "Meetme: %s\r\n"
02109                   "Usernum: %i\r\n"
02110                   "Status: on\r\n",
02111                   chan->name, chan->uniqueid, conf->confno, user->user_no);
02112          }
02113 
02114          /* If I should be un-muted but am not talker, un-mute me */
02115          if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & DAHDI_CONF_TALKER)) {
02116             ztc.confmode |= DAHDI_CONF_TALKER;
02117             if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
02118                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02119                ret = -1;
02120                break;
02121             }
02122 
02123             manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
02124                   "Channel: %s\r\n"
02125                   "Uniqueid: %s\r\n"
02126                   "Meetme: %s\r\n"
02127                   "Usernum: %i\r\n"
02128                   "Status: off\r\n",
02129                   chan->name, chan->uniqueid, conf->confno, user->user_no);
02130          }
02131 
02132          /* If I have been kicked, exit the conference */
02133          if (user->adminflags & ADMINFLAG_KICKME) {
02134             //You have been kicked.
02135             if (!(confflags & CONFFLAG_QUIET) && 
02136                !ast_streamfile(chan, "conf-kicked", chan->language)) {
02137                ast_waitstream(chan, "");
02138             }
02139             ret = 0;
02140             break;
02141          }
02142 
02143          c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
02144 
02145          if (c) {
02146             char dtmfstr[2] = "";
02147 
02148             if (c->fds[0] != origfd || (user->zapchannel && (c->audiohooks || c->monitor))) {
02149                if (using_pseudo) {
02150                   /* Kill old pseudo */
02151                   close(fd);
02152                   using_pseudo = 0;
02153                }
02154                ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
02155                retryzap = (strcasecmp(c->tech->type, dahdi_chan_name) || (c->audiohooks || c->monitor) ? 1 : 0);
02156                user->zapchannel = !retryzap;
02157                goto zapretry;
02158             }
02159             if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
02160                f = ast_read_noaudio(c);
02161             else
02162                f = ast_read(c);
02163             if (!f)
02164                break;
02165             if (f->frametype == AST_FRAME_DTMF) {
02166                dtmfstr[0] = f->subclass;
02167                dtmfstr[1] = '\0';
02168             }
02169 
02170             if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
02171                if (user->talk.actual)
02172                   ast_frame_adjust_volume(f, user->talk.actual);
02173 
02174                if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER)) {
02175                   if (user->talking == -1)
02176                      user->talking = 0;
02177 
02178                   res = ast_dsp_silence(dsp, f, &totalsilence);
02179                   if (totalsilence < MEETME_DELAYDETECTTALK) {
02180                      set_user_talking(chan, conf, user, 1, confflags & CONFFLAG_MONITORTALKER);
02181                   }
02182                   if (totalsilence > MEETME_DELAYDETECTENDTALK) {
02183                      set_user_talking(chan, conf, user, 0, confflags & CONFFLAG_MONITORTALKER);
02184                   }
02185                }
02186                if (using_pseudo) {
02187                   /* Absolutely do _not_ use careful_write here...
02188                      it is important that we read data from the channel
02189                      as fast as it arrives, and feed it into the conference.
02190                      The buffering in the pseudo channel will take care of any
02191                      timing differences, unless they are so drastic as to lose
02192                      audio frames (in which case carefully writing would only
02193                      have delayed the audio even further).
02194                   */
02195                   /* As it turns out, we do want to use careful write.  We just
02196                      don't want to block, but we do want to at least *try*
02197                      to write out all the samples.
02198                    */
02199                   if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER))
02200                      careful_write(fd, f->data, f->datalen, 0);
02201                }
02202             } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
02203                if (confflags & CONFFLAG_PASS_DTMF)
02204                   conf_queue_dtmf(conf, user, f);
02205                ret = 0;
02206                ast_frfree(f);
02207                break;
02208             } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
02209                if (confflags & CONFFLAG_PASS_DTMF)
02210                   conf_queue_dtmf(conf, user, f);
02211                if (ioctl(fd, DAHDI_SETCONF, &ztc_empty)) {
02212                   ast_log(LOG_WARNING, "Error setting conference\n");
02213                   close(fd);
02214                   ast_frfree(f);
02215                   goto outrun;
02216                }
02217 
02218                /* if we are entering the menu, and the user has a channel-driver
02219                   volume adjustment, clear it
02220                */
02221                if (!menu_active && user->talk.desired && !user->talk.actual)
02222                   set_talk_volume(user, 0);
02223 
02224                if (musiconhold) {
02225                      ast_moh_stop(chan);
02226                }
02227                if ((confflags & CONFFLAG_ADMIN)) {
02228                   /* Admin menu */
02229                   if (!menu_active) {
02230                      menu_active = 1;
02231                      /* Record this sound! */
02232                      if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
02233                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02234                         ast_stopstream(chan);
02235                      } else 
02236                         dtmf = 0;
02237                   } else 
02238                      dtmf = f->subclass;
02239                   if (dtmf) {
02240                      switch(dtmf) {
02241                      case '1': /* Un/Mute */
02242                         menu_active = 0;
02243 
02244                         /* for admin, change both admin and use flags */
02245                         if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
02246                            user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02247                         else
02248                            user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02249 
02250                         if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02251                            if (!ast_streamfile(chan, "conf-muted", chan->language))
02252                               ast_waitstream(chan, "");
02253                         } else {
02254                            if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02255                               ast_waitstream(chan, "");
02256                         }
02257                         break;
02258                      case '2': /* Un/Lock the Conference */
02259                         menu_active = 0;
02260                         if (conf->locked) {
02261                            conf->locked = 0;
02262                            if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
02263                               ast_waitstream(chan, "");
02264                         } else {
02265                            conf->locked = 1;
02266                            if (!ast_streamfile(chan, "conf-lockednow", chan->language))
02267                               ast_waitstream(chan, "");
02268                         }
02269                         break;
02270                      case '3': /* Eject last user */
02271                      {
02272                         struct ast_conf_user *usr = NULL;
02273                         int max_no = 0;
02274                         ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
02275                         menu_active = 0;
02276                         usr = ao2_find(conf->usercontainer, &max_no, 0);
02277                         if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
02278                            if(!ast_streamfile(chan, "conf-errormenu", chan->language))
02279                               ast_waitstream(chan, "");
02280                         } else {
02281                            usr->adminflags |= ADMINFLAG_KICKME;
02282                         }
02283                         ao2_ref(usr, -1);
02284                         ast_stopstream(chan);
02285                         break;   
02286                      }
02287                      case '4':
02288                         tweak_listen_volume(user, VOL_DOWN);
02289                         break;
02290                      case '6':
02291                         tweak_listen_volume(user, VOL_UP);
02292                         break;
02293                      case '7':
02294                         tweak_talk_volume(user, VOL_DOWN);
02295                         break;
02296                      case '8':
02297                         menu_active = 0;
02298                         break;
02299                      case '9':
02300                         tweak_talk_volume(user, VOL_UP);
02301                         break;
02302                      default:
02303                         menu_active = 0;
02304                         /* Play an error message! */
02305                         if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02306                            ast_waitstream(chan, "");
02307                         break;
02308                      }
02309                   }
02310                } else {
02311                   /* User menu */
02312                   if (!menu_active) {
02313                      menu_active = 1;
02314                      if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
02315                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02316                         ast_stopstream(chan);
02317                      } else
02318                         dtmf = 0;
02319                   } else 
02320                      dtmf = f->subclass;
02321                   if (dtmf) {
02322                      switch(dtmf) {
02323                      case '1': /* Un/Mute */
02324                         menu_active = 0;
02325 
02326                         /* user can only toggle the self-muted state */
02327                         user->adminflags ^= ADMINFLAG_SELFMUTED;
02328 
02329                         /* they can't override the admin mute state */
02330                         if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02331                            if (!ast_streamfile(chan, "conf-muted", chan->language))
02332                               ast_waitstream(chan, "");
02333                         } else {
02334                            if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02335                               ast_waitstream(chan, "");
02336                         }
02337                         break;
02338                      case '4':
02339                         tweak_listen_volume(user, VOL_DOWN);
02340                         break;
02341                      case '6':
02342                         tweak_listen_volume(user, VOL_UP);
02343                         break;
02344                      case '7':
02345                         tweak_talk_volume(user, VOL_DOWN);
02346                         break;
02347                      case '8':
02348                         menu_active = 0;
02349                         break;
02350                      case '9':
02351                         tweak_talk_volume(user, VOL_UP);
02352                         break;
02353                      default:
02354                         menu_active = 0;
02355                         if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02356                            ast_waitstream(chan, "");
02357                         break;
02358                      }
02359                   }
02360                }
02361                if (musiconhold) {
02362                      ast_moh_start(chan, NULL, NULL);
02363                }
02364 
02365                if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
02366                   ast_log(LOG_WARNING, "Error setting conference\n");
02367                   close(fd);
02368                   ast_frfree(f);
02369                   goto outrun;
02370                }
02371 
02372                conf_flush(fd, chan);
02373             /* Since this option could absorb dtmf for the previous, we have to check this one last */
02374             } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
02375                if (confflags & CONFFLAG_PASS_DTMF)
02376                   conf_queue_dtmf(conf, user, f);
02377 
02378                if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
02379                   ast_log(LOG_DEBUG, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
02380                   ret = 0;
02381                   ast_frfree(f);
02382                   break;
02383                } else if (option_debug > 1)
02384                   ast_log(LOG_DEBUG, "Exit by single digit did not work in meetme. Extension '%s' does not exist in context '%s'\n", dtmfstr, exitcontext);
02385             } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
02386                && confflags & CONFFLAG_PASS_DTMF) {
02387                conf_queue_dtmf(conf, user, f);
02388             } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
02389                switch (f->subclass) {
02390                case AST_CONTROL_HOLD:
02391                   sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
02392                   break;
02393                default:
02394                   break;
02395                }
02396             } else if (f->frametype == AST_FRAME_NULL) {
02397                /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
02398             } else if (f->frametype == AST_FRAME_CONTROL) {
02399                switch (f->subclass) {
02400                case AST_CONTROL_BUSY:
02401                case AST_CONTROL_CONGESTION:
02402                   ast_frfree(f);
02403                   goto outrun;
02404                   break;
02405                default:
02406                   if (option_debug) {
02407                      ast_log(LOG_DEBUG, 
02408                         "Got ignored control frame on channel %s, f->frametype=%d,f->subclass=%d\n",
02409                         chan->name, f->frametype, f->subclass);
02410                   }
02411                }
02412             } else if (option_debug) {
02413                ast_log(LOG_DEBUG,
02414                   "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
02415                   chan->name, f->frametype, f->subclass);
02416             }
02417             ast_frfree(f);
02418          } else if (outfd > -1) {
02419             res = read(outfd, buf, CONF_SIZE);
02420             if (res > 0) {
02421                memset(&fr, 0, sizeof(fr));
02422                fr.frametype = AST_FRAME_VOICE;
02423                fr.subclass = AST_FORMAT_SLINEAR;
02424                fr.datalen = res;
02425                fr.samples = res/2;
02426                fr.data = buf;
02427                fr.offset = AST_FRIENDLY_OFFSET;
02428                if (!user->listen.actual && 
02429                   ((confflags & CONFFLAG_MONITOR) || 
02430                    (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
02431                    (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
02432                    )) {
02433                   int index;
02434                   for (index=0;index<AST_FRAME_BITS;index++)
02435                      if (chan->rawwriteformat & (1 << index))
02436                         break;
02437                   if (index >= AST_FRAME_BITS)
02438                      goto bailoutandtrynormal;
02439                   ast_mutex_lock(&conf->listenlock);
02440                   if (!conf->transframe[index]) {
02441                      if (conf->origframe) {
02442                         if (musiconhold && !ast_dsp_silence(dsp, conf->origframe, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
02443                            ast_moh_stop(chan);
02444                            mohtempstopped = 1;
02445                         }
02446                         if (!conf->transpath[index])
02447                            conf->transpath[index] = ast_translator_build_path((1 << index), AST_FORMAT_SLINEAR);
02448                         if (conf->transpath[index]) {
02449                            conf->transframe[index] = ast_translate(conf->transpath[index], conf->origframe, 0);
02450                            if (!conf->transframe[index])
02451                               conf->transframe[index] = &ast_null_frame;
02452                         }
02453                      }
02454                   }
02455                   if (conf->transframe[index]) {
02456                      if ((conf->transframe[index]->frametype != AST_FRAME_NULL) &&
02457                          can_write(chan, confflags)) {
02458                         struct ast_frame *cur;
02459                         /* the translator may have returned a list of frames, so
02460                            write each one onto the channel
02461                         */
02462                         for (cur = conf->transframe[index]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
02463                            if (ast_write(chan, cur)) {
02464                               ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02465                               break;
02466                            }
02467                         }
02468                         if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
02469                            mohtempstopped = 0;
02470                            ast_moh_start(chan, NULL, NULL);
02471                         }
02472                      }
02473                   } else {
02474                      ast_mutex_unlock(&conf->listenlock);
02475                      goto bailoutandtrynormal;
02476                   }
02477                   ast_mutex_unlock(&conf->listenlock);
02478                } else {
02479 bailoutandtrynormal:
02480                   if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
02481                      ast_moh_stop(chan);
02482                      mohtempstopped = 1;
02483                   }
02484                   if (user->listen.actual)
02485                      ast_frame_adjust_volume(&fr, user->listen.actual);
02486                   if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
02487                      ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02488                   }
02489                   if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
02490                      mohtempstopped = 0;
02491                      ast_moh_start(chan, NULL, NULL);
02492                   }
02493                }
02494             } else 
02495                ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
02496          }
02497          lastmarked = currentmarked;
02498       }
02499    }
02500 
02501    if (musiconhold) {
02502       ast_moh_stop(chan);
02503    }
02504    
02505    if (using_pseudo)
02506       close(fd);
02507    else {
02508       /* Take out of conference */
02509       ztc.chan = 0;  
02510       ztc.confno = 0;
02511       ztc.confmode = 0;
02512       if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
02513          ast_log(LOG_WARNING, "Error setting conference\n");
02514       }
02515    }
02516 
02517    reset_volumes(user);
02518 
02519    if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
02520       conf_play(chan, conf, LEAVE);
02521 
02522    if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02523       struct announce_listitem *item;
02524       if (!(item = ao2_alloc(sizeof(*item), NULL)))
02525          goto outrun;
02526       ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02527       ast_copy_string(item->language, chan->language, sizeof(item->language));
02528       item->confchan = conf->chan;
02529       item->confusers = conf->users;
02530       item->announcetype = CONF_HASLEFT;
02531       ast_mutex_lock(&conf->announcelistlock);
02532       AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02533       ast_cond_signal(&conf->announcelist_addition);
02534       ast_mutex_unlock(&conf->announcelistlock);
02535    } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) {
02536       /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
02537       ast_filedelete(user->namerecloc, NULL);
02538    }
02539 
02540  outrun:
02541    AST_LIST_LOCK(&confs);
02542 
02543    if (dsp)
02544       ast_dsp_free(dsp);
02545    
02546    if (user->user_no) {
02547       /* Only cleanup users who really joined! */
02548       now = time(NULL);
02549       hr = (now - user->jointime) / 3600;
02550       min = ((now - user->jointime) % 3600) / 60;
02551       sec = (now - user->jointime) % 60;
02552 
02553       if (sent_event) {
02554          manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
02555                   "Channel: %s\r\n"
02556                   "Uniqueid: %s\r\n"
02557                   "Meetme: %s\r\n"
02558                   "Usernum: %d\r\n"
02559                   "CallerIDnum: %s\r\n"
02560                   "CallerIDname: %s\r\n"
02561                   "Duration: %ld\r\n",
02562                   chan->name, chan->uniqueid, conf->confno, 
02563                   user->user_no,
02564                   S_OR(user->chan->cid.cid_num, "<unknown>"),
02565                   S_OR(user->chan->cid.cid_name, "<unknown>"),
02566                   (long)(now - user->jointime));
02567       }
02568 
02569       if (setusercount) {
02570          conf->users--;
02571          /* Update table */
02572          snprintf(members, sizeof(members), "%d", conf->users);
02573          ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
02574          if (confflags & CONFFLAG_MARKEDUSER) 
02575             conf->markedusers--;
02576       }
02577       /* Remove ourselves from the container */
02578       ao2_unlink(conf->usercontainer, user); 
02579 
02580       /* Change any states */
02581       if (!conf->users)
02582          ast_device_state_changed("meetme:%s", conf->confno);
02583       
02584       /* Return the number of seconds the user was in the conf */
02585       snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
02586       pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
02587    }
02588    ao2_ref(user, -1);
02589    AST_LIST_UNLOCK(&confs);
02590 
02591    return ret;
02592 }

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

The MeetmeCount application.

Definition at line 2747 of file app_meetme.c.

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

Referenced by load_module().

02748 {
02749    struct ast_module_user *u;
02750    int res = 0;
02751    struct ast_conference *conf;
02752    int count;
02753    char *localdata;
02754    char val[80] = "0"; 
02755    AST_DECLARE_APP_ARGS(args,
02756       AST_APP_ARG(confno);
02757       AST_APP_ARG(varname);
02758    );
02759 
02760    if (ast_strlen_zero(data)) {
02761       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
02762       return -1;
02763    }
02764 
02765    u = ast_module_user_add(chan);
02766    
02767    if (!(localdata = ast_strdupa(data))) {
02768       ast_module_user_remove(u);
02769       return -1;
02770    }
02771 
02772    AST_STANDARD_APP_ARGS(args, localdata);
02773    
02774    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
02775 
02776    if (conf) {
02777       count = conf->users;
02778       dispose_conf(conf);
02779       conf = NULL;
02780    } else
02781       count = 0;
02782 
02783    if (!ast_strlen_zero(args.varname)){
02784       /* have var so load it and exit */
02785       snprintf(val, sizeof(val), "%d",count);
02786       pbx_builtin_setvar_helper(chan, args.varname, val);
02787    } else {
02788       if (chan->_state != AST_STATE_UP)
02789          ast_answer(chan);
02790       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
02791    }
02792    ast_module_user_remove(u);
02793 
02794    return res;
02795 }

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

Definition at line 4613 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

04614 {
04615    struct sla_trunk_ref *trunk_ref;
04616 
04617    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
04618       return NULL;
04619 
04620    trunk_ref->trunk = trunk;
04621 
04622    return trunk_ref;
04623 }

static void destroy_station ( struct sla_station station  )  [static]

Definition at line 4781 of file app_meetme.c.

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

Referenced by sla_destroy().

04782 {
04783    struct sla_trunk_ref *trunk_ref;
04784 
04785    if (!ast_strlen_zero(station->autocontext)) {
04786       AST_RWLIST_RDLOCK(&sla_trunks);
04787       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04788          char exten[AST_MAX_EXTENSION];
04789          char hint[AST_MAX_APP];
04790          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04791          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04792          ast_context_remove_extension(station->autocontext, exten, 
04793             1, sla_registrar);
04794          ast_context_remove_extension(station->autocontext, hint, 
04795             PRIORITY_HINT, sla_registrar);
04796       }
04797       AST_RWLIST_UNLOCK(&sla_trunks);
04798    }
04799 
04800    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
04801       free(trunk_ref);
04802 
04803    ast_string_field_free_memory(station);
04804    free(station);
04805 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

Definition at line 4767 of file app_meetme.c.

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

Referenced by sla_destroy().

04768 {
04769    struct sla_station_ref *station_ref;
04770 
04771    if (!ast_strlen_zero(trunk->autocontext))
04772       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
04773 
04774    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
04775       free(station_ref);
04776 
04777    ast_string_field_free_memory(trunk);
04778    free(trunk);
04779 }

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

Definition at line 4332 of file app_meetme.c.

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

Referenced by sla_station_exec().

04333 {
04334    struct dial_trunk_args *args = data;
04335    struct ast_dial *dial;
04336    char *tech, *tech_data;
04337    enum ast_dial_result dial_res;
04338    char conf_name[MAX_CONFNUM];
04339    struct ast_conference *conf;
04340    struct ast_flags conf_flags = { 0 };
04341    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
04342    const char *cid_name = NULL, *cid_num = NULL;
04343 
04344    if (!(dial = ast_dial_create())) {
04345       ast_mutex_lock(args->cond_lock);
04346       ast_cond_signal(args->cond);
04347       ast_mutex_unlock(args->cond_lock);
04348       return NULL;
04349    }
04350 
04351    tech_data = ast_strdupa(trunk_ref->trunk->device);
04352    tech = strsep(&tech_data, "/");
04353    if (ast_dial_append(dial, tech, tech_data) == -1) {
04354       ast_mutex_lock(args->cond_lock);
04355       ast_cond_signal(args->cond);
04356       ast_mutex_unlock(args->cond_lock);
04357       ast_dial_destroy(dial);
04358       return NULL;
04359    }
04360 
04361    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
04362       cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
04363       free(trunk_ref->chan->cid.cid_name);
04364       trunk_ref->chan->cid.cid_name = NULL;
04365    }
04366    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
04367       cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
04368       free(trunk_ref->chan->cid.cid_num);
04369       trunk_ref->chan->cid.cid_num = NULL;
04370    }
04371 
04372    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
04373 
04374    if (cid_name)
04375       trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
04376    if (cid_num)
04377       trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
04378 
04379    if (dial_res != AST_DIAL_RESULT_TRYING) {
04380       ast_mutex_lock(args->cond_lock);
04381       ast_cond_signal(args->cond);
04382       ast_mutex_unlock(args->cond_lock);
04383       ast_dial_destroy(dial);
04384       return NULL;
04385    }
04386 
04387    for (;;) {
04388       unsigned int done = 0;
04389       switch ((dial_res = ast_dial_state(dial))) {
04390       case AST_DIAL_RESULT_ANSWERED:
04391          trunk_ref->trunk->chan = ast_dial_answered(dial);
04392       case AST_DIAL_RESULT_HANGUP:
04393       case AST_DIAL_RESULT_INVALID:
04394       case AST_DIAL_RESULT_FAILED:
04395       case AST_DIAL_RESULT_TIMEOUT:
04396       case AST_DIAL_RESULT_UNANSWERED:
04397          done = 1;
04398       case AST_DIAL_RESULT_TRYING:
04399       case AST_DIAL_RESULT_RINGING:
04400       case AST_DIAL_RESULT_PROGRESS:
04401       case AST_DIAL_RESULT_PROCEEDING:
04402          break;
04403       }
04404       if (done)
04405          break;
04406    }
04407 
04408    if (!trunk_ref->trunk->chan) {
04409       ast_mutex_lock(args->cond_lock);
04410       ast_cond_signal(args->cond);
04411       ast_mutex_unlock(args->cond_lock);
04412       ast_dial_join(dial);
04413       ast_dial_destroy(dial);
04414       return NULL;
04415    }
04416 
04417    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04418    ast_set_flag(&conf_flags, 
04419       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
04420       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
04421    conf = build_conf(conf_name, "", "", 1, 1, 1);
04422 
04423    ast_mutex_lock(args->cond_lock);
04424    ast_cond_signal(args->cond);
04425    ast_mutex_unlock(args->cond_lock);
04426 
04427    if (conf) {
04428       conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
04429       dispose_conf(conf);
04430       conf = NULL;
04431    }
04432 
04433    /* If the trunk is going away, it is definitely now IDLE. */
04434    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04435 
04436    trunk_ref->trunk->chan = NULL;
04437    trunk_ref->trunk->on_hold = 0;
04438 
04439    ast_dial_join(dial);
04440    ast_dial_destroy(dial);
04441 
04442    return NULL;
04443 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Definition at line 1463 of file app_meetme.c.

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

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

01464 {
01465    int res = 0;
01466    int confno_int = 0;
01467 
01468    AST_LIST_LOCK(&confs);
01469    if (ast_atomic_dec_and_test(&conf->refcount)) {
01470       /* Take the conference room number out of an inuse state */
01471       if ((sscanf(conf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01472          conf_map[confno_int] = 0;
01473       conf_free(conf);
01474       res = 1;
01475    }
01476    AST_LIST_UNLOCK(&confs);
01477 
01478    return res;
01479 }

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

Definition at line 2652 of file app_meetme.c.

References AST_APP_ARG, ast_app_getdata(), ast_config_destroy(), ast_config_load(), ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_variable_browse(), build_conf(), ast_conference::chan, CONFIG_FILE_NAME, ast_conference::confno, ast_conference::list, LOG_DEBUG, LOG_WARNING, MAX_SETTINGS, parse(), ast_conference::refcount, S_OR, and var.

Referenced by conf_exec(), and count_exec().

02654 {
02655    struct ast_config *cfg;
02656    struct ast_variable *var;
02657    struct ast_conference *cnf;
02658    AST_DECLARE_APP_ARGS(args,
02659       AST_APP_ARG(confno);
02660       AST_APP_ARG(pin);
02661       AST_APP_ARG(pinadmin);
02662    );
02663 
02664    /* Check first in the conference list */
02665    AST_LIST_LOCK(&confs);
02666    AST_LIST_TRAVERSE(&confs, cnf, list) {
02667       if (!strcmp(confno, cnf->confno)) 
02668          break;
02669    }
02670    if (cnf){
02671       cnf->refcount += refcount;
02672    }
02673    AST_LIST_UNLOCK(&confs);
02674 
02675    if (!cnf) {
02676       if (dynamic) {
02677          /* No need to parse meetme.conf */
02678          ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
02679          if (dynamic_pin) {
02680             if (dynamic_pin[0] == 'q') {
02681                /* Query the user to enter a PIN */
02682                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
02683                   return NULL;
02684             }
02685             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount);
02686          } else {
02687             cnf = build_conf(confno, "", "", make, dynamic, refcount);
02688          }
02689       } else {
02690          /* Check the config */
02691          cfg = ast_config_load(CONFIG_FILE_NAME);
02692          if (!cfg) {
02693             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
02694             return NULL;
02695          }
02696 
02697          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
02698             char parse[MAX_SETTINGS];
02699 
02700             if (strcasecmp(var->name, "conf"))
02701                continue;
02702 
02703             ast_copy_string(parse, var->value, sizeof(parse));
02704 
02705             AST_NONSTANDARD_APP_ARGS(args, parse, ',');
02706             if (!strcasecmp(args.confno, confno)) {
02707                /* Bingo it's a valid conference */
02708                cnf = build_conf(args.confno,
02709                      S_OR(args.pin, ""),
02710                      S_OR(args.pinadmin, ""),
02711                      make, dynamic, refcount);
02712                break;
02713             }
02714          }
02715          if (!var) {
02716             ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
02717          }
02718          ast_config_destroy(cfg);
02719       }
02720    } else if (dynamic_pin) {
02721       /* Correct for the user selecting 'D' instead of 'd' to have
02722          someone join into a conference that has already been created
02723          with a pin. */
02724       if (dynamic_pin[0] == 'q')
02725          dynamic_pin[0] = '\0';
02726    }
02727 
02728    if (cnf) {
02729       if (confflags && !cnf->chan &&
02730           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
02731           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
02732          ast_log(LOG_WARNING, "No %s channel available for conference, user introduction disabled\n", dahdi_chan_name);
02733          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
02734       }
02735       
02736       if (confflags && !cnf->chan &&
02737           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
02738          ast_log(LOG_WARNING, "No %s channel available for conference, conference recording disabled\n", dahdi_chan_name);
02739          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
02740       }
02741    }
02742 
02743    return cnf;
02744 }

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 
) [static]

Definition at line 2594 of file app_meetme.c.

References ast_clear_flag, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_log(), ast_strdupa, ast_test_flag, ast_variables_destroy(), build_conf(), ast_conference::chan, CONFFLAG_RECORDCONF, ast_conference::confno, dahdi_chan_name, ast_conference::list, LOG_WARNING, ast_conference::refcount, and var.

Referenced by conf_exec().

02596 {
02597    struct ast_variable *var, *save;
02598    struct ast_conference *cnf;
02599 
02600    /* Check first in the conference list */
02601    AST_LIST_LOCK(&confs);
02602    AST_LIST_TRAVERSE(&confs, cnf, list) {
02603       if (!strcmp(confno, cnf->confno)) 
02604          break;
02605    }
02606    if (cnf) {
02607       cnf->refcount += refcount;
02608    }
02609    AST_LIST_UNLOCK(&confs);
02610 
02611    if (!cnf) {
02612       char *pin = NULL, *pinadmin = NULL; /* For temp use */
02613       
02614       var = ast_load_realtime("meetme", "confno", confno, NULL);
02615 
02616       if (!var)
02617          return NULL;
02618 
02619       save = var;
02620       while (var) {
02621          if (!strcasecmp(var->name, "pin")) {
02622             pin = ast_strdupa(var->value);
02623          } else if (!strcasecmp(var->name, "adminpin")) {
02624             pinadmin = ast_strdupa(var->value);
02625          }
02626          var = var->next;
02627       }
02628       ast_variables_destroy(save);
02629       
02630       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount);
02631    }
02632 
02633    if (cnf) {
02634       if (confflags && !cnf->chan &&
02635           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
02636           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
02637          ast_log(LOG_WARNING, "No %s channel available for conference, user introduction disabled\n", dahdi_chan_name);
02638          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
02639       }
02640       
02641       if (confflags && !cnf->chan &&
02642           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
02643          ast_log(LOG_WARNING, "No %s channel available for conference, conference recording disabled\n", dahdi_chan_name);
02644          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
02645       }
02646    }
02647 
02648    return cnf;
02649 }

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

Definition at line 3049 of file app_meetme.c.

References ao2_find(), and ast_conference::usercontainer.

03050 {
03051    struct ast_conf_user *user = NULL;
03052    int cid;
03053    
03054    sscanf(callerident, "%30i", &cid);
03055    if (conf && callerident) {
03056       user = ao2_find(conf->usercontainer, &cid, 0);
03057       /* reference decremented later in admin_exec */
03058       return user;
03059    }
03060    return NULL;
03061 }

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

Definition at line 1481 of file app_meetme.c.

References CONF_HASJOIN.

Referenced by announce_thread().

01482 {
01483    switch (type) {
01484    case CONF_HASLEFT:
01485       return "conf-hasleft";
01486       break;
01487    case CONF_HASJOIN:
01488       return "conf-hasjoin";
01489       break;
01490    default:
01491       return "";
01492    }
01493 }

static char* istalking ( int  x  )  [static]

Definition at line 599 of file app_meetme.c.

Referenced by meetme_cmd().

00600 {
00601    if (x > 0)
00602       return "(talking)";
00603    else if (x < 0)
00604       return "(unmonitored)";
00605    else 
00606       return "(not talking)";
00607 }

static int load_config ( int  reload  )  [static]

Definition at line 5136 of file app_meetme.c.

References load_config_meetme(), and sla_load_config().

05137 {
05138    int res = 0;
05139 
05140    load_config_meetme();
05141    if (!reload)
05142       res = sla_load_config();
05143 
05144    return res;
05145 }

static void load_config_meetme ( void   )  [static]

Definition at line 3414 of file app_meetme.c.

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

Referenced by load_config().

03415 {
03416    struct ast_config *cfg;
03417    const char *val;
03418 
03419    audio_buffers = DEFAULT_AUDIO_BUFFERS;
03420 
03421    if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
03422       return;
03423 
03424    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03425       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
03426          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03427          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03428       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
03429          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03430             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
03431          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03432       }
03433       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03434          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03435    }
03436 
03437    ast_config_destroy(cfg);
03438 }

static int load_module ( void   )  [static]

Definition at line 5170 of file app_meetme.c.

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

05171 {
05172    int res = 0;
05173 
05174    res |= load_config(0);
05175 
05176    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05177    res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 
05178                 action_meetmemute, "Mute a Meetme user");
05179    res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 
05180                 action_meetmeunmute, "Unmute a Meetme user");
05181    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
05182    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
05183    res |= ast_register_application(app, conf_exec, synopsis, descrip);
05184    res |= ast_register_application(slastation_app, sla_station_exec,
05185                slastation_synopsis, slastation_desc);
05186    res |= ast_register_application(slatrunk_app, sla_trunk_exec,
05187                slatrunk_synopsis, slatrunk_desc);
05188 
05189    res |= ast_devstate_prov_add("Meetme", meetmestate);
05190    res |= ast_devstate_prov_add("SLA", sla_state);
05191 
05192    return res;
05193 }

static int meetme_cmd ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 895 of file app_meetme.c.

References admin_exec(), ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ast_cli(), ast_copy_string(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_conference::isdynamic, istalking(), ast_conf_user::jointime, ast_conf_user::list, LOG_DEBUG, ast_conference::markedusers, ast_channel::name, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_OR, ast_conference::start, ast_conf_user::talking, total, ast_conf_user::user_no, ast_conference::usercontainer, ast_conf_user::userflags, and ast_conference::users.

00896 {
00897    /* Process the command */
00898    struct ast_conference *cnf;
00899    struct ast_conf_user *user;
00900    int hr, min, sec;
00901    int i = 0, total = 0;
00902    time_t now;
00903    char *header_format = "%-14s %-14s %-10s %-8s  %-8s\n";
00904    char *data_format = "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s\n";
00905    char cmdline[1024] = "";
00906 
00907    if (argc > 8)
00908       ast_cli(fd, "Invalid Arguments.\n");
00909    /* Check for length so no buffer will overflow... */
00910    for (i = 0; i < argc; i++) {
00911       if (strlen(argv[i]) > 100)
00912          ast_cli(fd, "Invalid Arguments.\n");
00913    }
00914    if (argc == 1) {
00915       /* 'MeetMe': List all the conferences */  
00916       now = time(NULL);
00917       AST_LIST_LOCK(&confs);
00918       if (AST_LIST_EMPTY(&confs)) {
00919          ast_cli(fd, "No active MeetMe conferences.\n");
00920          AST_LIST_UNLOCK(&confs);
00921          return RESULT_SUCCESS;
00922       }
00923       ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
00924       AST_LIST_TRAVERSE(&confs, cnf, list) {
00925          if (cnf->markedusers == 0)
00926             strcpy(cmdline, "N/A ");
00927          else 
00928             snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers);
00929          hr = (now - cnf->start) / 3600;
00930          min = ((now - cnf->start) % 3600) / 60;
00931          sec = (now - cnf->start) % 60;
00932 
00933          ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static");
00934 
00935          total += cnf->users;    
00936       }
00937       AST_LIST_UNLOCK(&confs);
00938       ast_cli(fd, "* Total number of MeetMe users: %d\n", total);
00939       return RESULT_SUCCESS;
00940    }
00941    if (argc < 3)
00942       return RESULT_SHOWUSAGE;
00943    ast_copy_string(cmdline, argv[2], sizeof(cmdline));   /* Argv 2: conference number */
00944    if (strstr(argv[1], "lock")) {   
00945       if (strcmp(argv[1], "lock") == 0) {
00946          /* Lock */
00947          strncat(cmdline, "|L", sizeof(cmdline) - strlen(cmdline) - 1);
00948       } else {
00949          /* Unlock */
00950          strncat(cmdline, "|l", sizeof(cmdline) - strlen(cmdline) - 1);
00951       }
00952    } else if (strstr(argv[1], "mute")) { 
00953       if (argc < 4)
00954          return RESULT_SHOWUSAGE;
00955       if (strcmp(argv[1], "mute") == 0) {
00956          /* Mute */
00957          if (strcmp(argv[3], "all") == 0) {
00958             strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1);
00959          } else {
00960             strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1);   
00961             strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00962          }
00963       } else {
00964          /* Unmute */
00965          if (strcmp(argv[3], "all") == 0) {
00966             strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1);
00967          } else {
00968             strncat(cmdline, "|m|", sizeof(cmdline) - strlen(cmdline) - 1);
00969             strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00970          }
00971       }
00972    } else if (strcmp(argv[1], "kick") == 0) {
00973       if (argc < 4)
00974          return RESULT_SHOWUSAGE;
00975       if (strcmp(argv[3], "all") == 0) {
00976          /* Kick all */
00977          strncat(cmdline, "|K", sizeof(cmdline) - strlen(cmdline) - 1);
00978       } else {
00979          /* Kick a single user */
00980          strncat(cmdline, "|k|", sizeof(cmdline) - strlen(cmdline) - 1);
00981          strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00982       }  
00983    } else if(strcmp(argv[1], "list") == 0) {
00984       struct ao2_iterator user_iter;
00985       int concise = ( 4 == argc && ( !strcasecmp(argv[3], "concise") ) );
00986       /* List all the users in a conference */
00987       if (AST_LIST_EMPTY(&confs)) {
00988          if ( !concise )
00989             ast_cli(fd, "No active conferences.\n");
00990          return RESULT_SUCCESS;  
00991       }
00992       /* Find the right conference */
00993       AST_LIST_LOCK(&confs);
00994       AST_LIST_TRAVERSE(&confs, cnf, list) {
00995          if (strcmp(cnf->confno, argv[2]) == 0)
00996             break;
00997       }
00998       if (!cnf) {
00999          if ( !concise )
01000             ast_cli(fd, "No such conference: %s.\n",argv[2]);
01001          AST_LIST_UNLOCK(&confs);
01002          return RESULT_SUCCESS;
01003       }
01004       /* Show all the users */
01005       time(&now);
01006       user_iter = ao2_iterator_init(cnf->usercontainer, 0);
01007       while((user = ao2_iterator_next(&user_iter))) {
01008          hr = (now - user->jointime) / 3600;
01009          min = ((now - user->jointime) % 3600) / 60;
01010          sec = (now - user->jointime) % 60;
01011          if (!concise) {
01012             ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %02d:%02d:%02d\n",
01013                user->user_no,
01014                S_OR(user->chan->cid.cid_num, "<unknown>"),
01015                S_OR(user->chan->cid.cid_name, "<no name>"),
01016                user->chan->name,
01017                user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
01018                user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
01019                user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
01020                istalking(user->talking), hr, min, sec); 
01021          } else {
01022             ast_cli(fd, "%d!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
01023                user->user_no,
01024                S_OR(user->chan->cid.cid_num, ""),
01025                S_OR(user->chan->cid.cid_name, ""),
01026                user->chan->name,
01027                user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
01028                user->userflags  & CONFFLAG_MONITOR ? "1" : "",
01029                user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)  ? "1" : "",
01030                user->talking, hr, min, sec);
01031          }
01032          ao2_ref(user, -1);
01033       }
01034       ao2_iterator_destroy(&user_iter);
01035       if ( !concise )
01036          ast_cli(fd,"%d users in that conference.\n",cnf->users);
01037       AST_LIST_UNLOCK(&confs);
01038       return RESULT_SUCCESS;
01039    } else 
01040       return RESULT_SHOWUSAGE;
01041    ast_log(LOG_DEBUG, "Cmdline: %s\n", cmdline);
01042    admin_exec(NULL, cmdline);
01043 
01044    return 0;
01045 }

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

Definition at line 3257 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, ao2_find(), ao2_ref(), 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, s, ast_channel::uniqueid, ast_conf_user::user_no, and ast_conference::usercontainer.

Referenced by action_meetmemute(), and action_meetmeunmute().

03258 {
03259    struct ast_conference *conf;
03260    struct ast_conf_user *user;
03261    const char *confid = astman_get_header(m, "Meetme");
03262    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
03263    int userno;
03264 
03265    if (ast_strlen_zero(confid)) {
03266       astman_send_error(s, m, "Meetme conference not specified");
03267       return 0;
03268    }
03269 
03270    if (ast_strlen_zero(userid)) {
03271       astman_send_error(s, m, "Meetme user number not specified");
03272       return 0;
03273    }
03274 
03275    userno = strtoul(userid, &userid, 10);
03276 
03277    if (*userid) {
03278       astman_send_error(s, m, "Invalid user number");
03279       return 0;
03280    }
03281 
03282    /* Look in the conference list */
03283    AST_LIST_LOCK(&confs);
03284    AST_LIST_TRAVERSE(&confs, conf, list) {
03285       if (!strcmp(confid, conf->confno))
03286          break;
03287    }
03288 
03289    if (!conf) {
03290       AST_LIST_UNLOCK(&confs);
03291       astman_send_error(s, m, "Meetme conference does not exist");
03292       return 0;
03293    }
03294 
03295    user = ao2_find(conf->usercontainer, &userno, 0);
03296 
03297    if (!user) {
03298       AST_LIST_UNLOCK(&confs);
03299       astman_send_error(s, m, "User number not found");
03300       return 0;
03301    }
03302 
03303    if (mute)
03304       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
03305    else
03306       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);  /* request user unmuting */
03307 
03308    AST_LIST_UNLOCK(&confs);
03309 
03310    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);
03311 
03312    ao2_ref(user, -1);
03313    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
03314    return 0;
03315 }

static int meetmestate ( const char *  data  )  [static]

Callback for devicestate providers.

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

03393 {
03394    struct ast_conference *conf;
03395 
03396    /* Find conference */
03397    AST_LIST_LOCK(&confs);
03398    AST_LIST_TRAVERSE(&confs, conf, list) {
03399       if (!strcmp(data, conf->confno))
03400          break;
03401    }
03402    AST_LIST_UNLOCK(&confs);
03403    if (!conf)
03404       return AST_DEVICE_INVALID;
03405 
03406 
03407    /* SKREP to fill */
03408    if (!conf->users)
03409       return AST_DEVICE_NOT_INUSE;
03410 
03411    return AST_DEVICE_INUSE;
03412 }

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

Definition at line 4625 of file app_meetme.c.

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

Referenced by sla_trunk_exec().

04626 {
04627    struct sla_ringing_trunk *ringing_trunk;
04628 
04629    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
04630       return NULL;
04631    
04632    ringing_trunk->trunk = trunk;
04633    ringing_trunk->ring_begin = ast_tvnow();
04634 
04635    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
04636 
04637    ast_mutex_lock(&sla.lock);
04638    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
04639    ast_mutex_unlock(&sla.lock);
04640 
04641    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04642 
04643    return ringing_trunk;
04644 }

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

Definition at line 3327 of file app_meetme.c.

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

03328 {
03329    struct ast_conference *cnf = args;
03330    struct ast_frame *f=NULL;
03331    int flags;
03332    struct ast_filestream *s=NULL;
03333    int res=0;
03334    int x;
03335    const char *oldrecordingfilename = NULL;
03336 
03337    if (!cnf || !cnf->lchan) {
03338       pthread_exit(0);
03339    }
03340 
03341    ast_stopstream(cnf->lchan);
03342    flags = O_CREAT|O_TRUNC|O_WRONLY;
03343 
03344 
03345    cnf->recording = MEETME_RECORD_ACTIVE;
03346    while (ast_waitfor(cnf->lchan, -1) > -1) {
03347       if (cnf->recording == MEETME_RECORD_TERMINATE) {
03348          AST_LIST_LOCK(&confs);
03349          AST_LIST_UNLOCK(&confs);
03350          break;
03351       }
03352       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
03353          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
03354          oldrecordingfilename = cnf->recordingfilename;
03355       }
03356       
03357       f = ast_read(cnf->lchan);
03358       if (!f) {
03359          res = -1;
03360          break;
03361       }
03362       if (f->frametype == AST_FRAME_VOICE) {
03363          ast_mutex_lock(&cnf->listenlock);
03364          for (x=0;x<AST_FRAME_BITS;x++) {
03365             /* Free any translations that have occured */
03366             if (cnf->transframe[x]) {
03367                ast_frfree(cnf->transframe[x]);
03368                cnf->transframe[x] = NULL;
03369             }
03370          }
03371          if (cnf->origframe)
03372             ast_frfree(cnf->origframe);
03373          cnf->origframe = ast_frdup(f);
03374          ast_mutex_unlock(&cnf->listenlock);
03375          if (s)
03376             res = ast_writestream(s, f);
03377          if (res) {
03378             ast_frfree(f);
03379             break;
03380          }
03381       }
03382       ast_frfree(f);
03383    }
03384    cnf->recording = MEETME_RECORD_OFF;
03385    if (s)
03386       ast_closestream(s);
03387    
03388    pthread_exit(0);
03389 }

static int reload ( void   )  [static]

Definition at line 5195 of file app_meetme.c.

References load_config().

05196 {
05197    return load_config(1);
05198 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

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

00720 {
00721    signed char zero_volume = 0;
00722 
00723    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00724    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00725 }

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

Definition at line 3579 of file app_meetme.c.

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

Referenced by sla_handle_dial_state_event().

03580 {
03581    struct sla_station *station;
03582    struct sla_trunk_ref *trunk_ref;
03583    char conf_name[MAX_CONFNUM];
03584    struct ast_flags conf_flags = { 0 };
03585    struct ast_conference *conf;
03586 
03587    {
03588       struct run_station_args *args = data;
03589       station = args->station;
03590       trunk_ref = args->trunk_ref;
03591       ast_mutex_lock(args->cond_lock);
03592       ast_cond_signal(args->cond);
03593       ast_mutex_unlock(args->cond_lock);
03594       /* args is no longer valid here. */
03595    }
03596 
03597    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
03598    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
03599    ast_set_flag(&conf_flags, 
03600       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
03601    answer_trunk_chan(trunk_ref->chan);
03602    conf = build_conf(conf_name, "", "", 0, 0, 1);
03603    if (conf) {
03604       conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
03605       dispose_conf(conf);
03606       conf = NULL;
03607    }
03608    trunk_ref->chan = NULL;
03609    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
03610       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
03611       strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
03612       admin_exec(NULL, conf_name);
03613       trunk_ref->trunk->hold_stations = 0;
03614       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03615    }
03616 
03617    ast_dial_join(station->dial);
03618    ast_dial_destroy(station->dial);
03619    station->dial = NULL;
03620 
03621    return NULL;
03622 }

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

Definition at line 1557 of file app_meetme.c.

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

Referenced by set_user_talking().

01558 {
01559    manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
01560          "Channel: %s\r\n"
01561          "Uniqueid: %s\r\n"
01562          "Meetme: %s\r\n"
01563          "Usernum: %d\r\n"
01564          "Status: %s\r\n",
01565          chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
01566 }

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

Definition at line 648 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

00649 {
00650    char gain_adjust;
00651 
00652    /* attempt to make the adjustment in the channel driver;
00653       if successful, don't adjust in the frame reading routine
00654    */
00655    gain_adjust = gain_map[volume + 5];
00656 
00657    return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00658 }

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

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

00637 {
00638    char gain_adjust;
00639 
00640    /* attempt to make the adjustment in the channel driver;
00641       if successful, don't adjust in the frame reading routine
00642    */
00643    gain_adjust = gain_map[volume + 5];
00644 
00645    return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00646 }

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

Definition at line 1568 of file app_meetme.c.

References ast_conference::chan, send_talking_event(), and ast_conf_user::talking.

Referenced by conf_run().

01569 {
01570    int last_talking = user->talking;
01571    if (last_talking == talking)
01572       return;
01573 
01574    user->talking = talking;
01575 
01576    if (monitor) {
01577       /* Check if talking state changed. Take care of -1 which means unmonitored */
01578       int was_talking = (last_talking > 0);
01579       int now_talking = (talking > 0);
01580       if (was_talking != now_talking) {
01581          send_talking_event(chan, conf, user, now_talking);
01582       }
01583    }
01584 }

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

Definition at line 4928 of file app_meetme.c.

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

Referenced by sla_build_station().

04929 {
04930    struct sla_trunk *trunk;
04931    struct sla_trunk_ref *trunk_ref;
04932    struct sla_station_ref *station_ref;
04933    char *trunk_name, *options, *cur;
04934 
04935    options = ast_strdupa(var->value);
04936    trunk_name = strsep(&options, ",");
04937    
04938    AST_RWLIST_RDLOCK(&sla_trunks);
04939    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04940       if (!strcasecmp(trunk->name, trunk_name))
04941          break;
04942    }
04943 
04944    AST_RWLIST_UNLOCK(&sla_trunks);
04945    if (!trunk) {
04946       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
04947       return;
04948    }
04949    if (!(trunk_ref = create_trunk_ref(trunk)))
04950       return;
04951    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
04952 
04953    while ((cur = strsep(&options, ","))) {
04954       char *name, *value = cur;
04955       name = strsep(&value, "=");
04956       if (!strcasecmp(name, "ringtimeout")) {
04957          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
04958             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
04959                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04960             trunk_ref->ring_timeout = 0;
04961          }
04962       } else if (!strcasecmp(name, "ringdelay")) {
04963          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
04964             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
04965                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04966             trunk_ref->ring_delay = 0;
04967          }
04968       } else {
04969          ast_log(LOG_WARNING, "Invalid option '%s' for "
04970             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
04971       }
04972    }
04973 
04974    if (!(station_ref = sla_create_station_ref(station))) {
04975       free(trunk_ref);
04976       return;
04977    }
04978    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
04979    AST_RWLIST_WRLOCK(&sla_trunks);
04980    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
04981    AST_RWLIST_UNLOCK(&sla_trunks);
04982    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
04983 }

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

Definition at line 4985 of file app_meetme.c.

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

Referenced by sla_load_config().

04986 {
04987    struct sla_station *station;
04988    struct ast_variable *var;
04989    const char *dev;
04990 
04991    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
04992       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
04993       return -1;
04994    }
04995 
04996    if (!(station = ast_calloc(1, sizeof(*station))))
04997       return -1;
04998    if (ast_string_field_init(station, 32)) {
04999       free(station);
05000       return -1;
05001    }
05002 
05003    ast_string_field_set(station, name, cat);
05004    ast_string_field_set(station, device, dev);
05005 
05006    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05007       if (!strcasecmp(var->name, "trunk"))
05008          sla_add_trunk_to_station(station, var);
05009       else if (!strcasecmp(var->name, "autocontext"))
05010          ast_string_field_set(station, autocontext, var->value);
05011       else if (!strcasecmp(var->name, "ringtimeout")) {
05012          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
05013             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
05014                var->value, station->name);
05015             station->ring_timeout = 0;
05016          }
05017       } else if (!strcasecmp(var->name, "ringdelay")) {
05018          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
05019             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
05020                var->value, station->name);
05021             station->ring_delay = 0;
05022          }
05023       } else if (!strcasecmp(var->name, "hold")) {
05024          if (!strcasecmp(var->value, "private"))
05025             station->hold_access = SLA_HOLD_PRIVATE;
05026          else if (!strcasecmp(var->value, "open"))
05027             station->hold_access = SLA_HOLD_OPEN;
05028          else {
05029             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
05030                var->value, station->name);
05031          }
05032 
05033       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05034          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05035             var->name, var->lineno, SLA_CONFIG_FILE);
05036       }
05037    }
05038 
05039    if (!ast_strlen_zero(station->autocontext)) {
05040       struct ast_context *context;
05041       struct sla_trunk_ref *trunk_ref;
05042       context = ast_context_find_or_create(NULL, station->autocontext, sla_registrar);
05043       if (!context) {
05044          ast_log(LOG_ERROR, "Failed to automatically find or create "
05045             "context '%s' for SLA!\n", station->autocontext);
05046          destroy_station(station);
05047          return -1;
05048       }
05049       /* The extension for when the handset goes off-hook.
05050        * exten => station1,1,SLAStation(station1) */
05051       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
05052          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
05053          ast_log(LOG_ERROR, "Failed to automatically create extension "
05054             "for trunk '%s'!\n", station->name);
05055          destroy_station(station);
05056          return -1;
05057       }
05058       AST_RWLIST_RDLOCK(&sla_trunks);
05059       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05060          char exten[AST_MAX_EXTENSION];
05061          char hint[AST_MAX_APP];
05062          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05063          snprintf(hint, sizeof(hint), "SLA:%s", exten);
05064          /* Extension for this line button 
05065           * exten => station1_line1,1,SLAStation(station1_line1) */
05066          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
05067             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
05068             ast_log(LOG_ERROR, "Failed to automatically create extension "
05069                "for trunk '%s'!\n", station->name);
05070             destroy_station(station);
05071             return -1;
05072          }
05073          /* Hint for this line button 
05074           * exten => station1_line1,hint,SLA:station1_line1 */
05075          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
05076             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
05077             ast_log(LOG_ERROR, "Failed to automatically create hint "
05078                "for trunk '%s'!\n", station->name);
05079             destroy_station(station);
05080             return -1;
05081          }
05082       }
05083       AST_RWLIST_UNLOCK(&sla_trunks);
05084    }
05085 
05086    AST_RWLIST_WRLOCK(&sla_stations);
05087    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
05088    AST_RWLIST_UNLOCK(&sla_stations);
05089 
05090    return 0;
05091 }

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

Definition at line 4850 of file app_meetme.c.

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

Referenced by sla_load_config().

04851 {
04852    struct sla_trunk *trunk;
04853    struct ast_variable *var;
04854    const char *dev;
04855 
04856    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
04857       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
04858       return -1;
04859    }
04860 
04861    if (sla_check_device(dev)) {
04862       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
04863          cat, dev);
04864       return -1;
04865    }
04866 
04867    if (!(trunk = ast_calloc(1, sizeof(*trunk))))
04868       return -1;
04869    if (ast_string_field_init(trunk, 32)) {
04870       free(trunk);
04871       return -1;
04872    }
04873 
04874    ast_string_field_set(trunk, name, cat);
04875    ast_string_field_set(trunk, device, dev);
04876 
04877    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04878       if (!strcasecmp(var->name, "autocontext"))
04879          ast_string_field_set(trunk, autocontext, var->value);
04880       else if (!strcasecmp(var->name, "ringtimeout")) {
04881          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
04882             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
04883                var->value, trunk->name);
04884             trunk->ring_timeout = 0;
04885          }
04886       } else if (!strcasecmp(var->name, "barge"))
04887          trunk->barge_disabled = ast_false(var->value);
04888       else if (!strcasecmp(var->name, "hold")) {
04889          if (!strcasecmp(var->value, "private"))
04890             trunk->hold_access = SLA_HOLD_PRIVATE;
04891          else if (!strcasecmp(var->value, "open"))
04892             trunk->hold_access = SLA_HOLD_OPEN;
04893          else {
04894             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
04895                var->value, trunk->name);
04896          }
04897       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
04898          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
04899             var->name, var->lineno, SLA_CONFIG_FILE);
04900       }
04901    }
04902 
04903    if (!ast_strlen_zero(trunk->autocontext)) {
04904       struct ast_context *context;
04905       context = ast_context_find_or_create(NULL, trunk->autocontext, sla_registrar);
04906       if (!context) {
04907          ast_log(LOG_ERROR, "Failed to automatically find or create "
04908             "context '%s' for SLA!\n", trunk->autocontext);
04909          destroy_trunk(trunk);
04910          return -1;
04911       }
04912       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
04913          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
04914          ast_log(LOG_ERROR, "Failed to automatically create extension "
04915             "for trunk '%s'!\n", trunk->name);
04916          destroy_trunk(trunk);
04917          return -1;
04918       }
04919    }
04920 
04921    AST_RWLIST_WRLOCK(&sla_trunks);
04922    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
04923    AST_RWLIST_UNLOCK(&sla_trunks);
04924 
04925    return 0;
04926 }

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

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

Referenced by sla_process_timers().

04197 {
04198    struct sla_station *station;
04199    int res = 0;
04200 
04201    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04202       struct sla_ringing_trunk *ringing_trunk;
04203       int time_left;
04204 
04205       /* Ignore stations already ringing */
04206       if (sla_check_ringing_station(station))
04207          continue;
04208 
04209       /* Ignore stations already on a call */
04210       if (sla_check_inuse_station(station))
04211          continue;
04212 
04213       /* Ignore stations that don't have one of their trunks ringing */
04214       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
04215          continue;
04216 
04217       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
04218          continue;
04219 
04220       /* If there is no time left, then the station needs to start ringing.
04221        * Return non-zero so that an event will be queued up an event to 
04222        * make that happen. */
04223       if (time_left <= 0) {
04224          res = 1;
04225          continue;
04226       }
04227 
04228       if (time_left < *timeout)
04229          *timeout = time_left;
04230    }
04231 
04232    return res;
04233 }

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

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

Referenced by sla_process_timers().

04114 {
04115    struct sla_ringing_trunk *ringing_trunk;
04116    struct sla_ringing_station *ringing_station;
04117    int res = 0;
04118 
04119    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04120       unsigned int ring_timeout = 0;
04121       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
04122       struct sla_trunk_ref *trunk_ref;
04123 
04124       /* If there are any ring timeouts specified for a specific trunk
04125        * on the station, then use the highest per-trunk ring timeout.
04126        * Otherwise, use the ring timeout set for the entire station. */
04127       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04128          struct sla_station_ref *station_ref;
04129          int trunk_time_elapsed, trunk_time_left;
04130 
04131          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04132             if (ringing_trunk->trunk == trunk_ref->trunk)
04133                break;
04134          }
04135          if (!ringing_trunk)
04136             continue;
04137 
04138          /* If there is a trunk that is ringing without a timeout, then the
04139           * only timeout that could matter is a global station ring timeout. */
04140          if (!trunk_ref->ring_timeout)
04141             break;
04142 
04143          /* This trunk on this station is ringing and has a timeout.
04144           * However, make sure this trunk isn't still ringing from a
04145           * previous timeout.  If so, don't consider it. */
04146          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
04147             if (station_ref->station == ringing_station->station)
04148                break;
04149          }
04150          if (station_ref)
04151             continue;
04152 
04153          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04154          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
04155          if (trunk_time_left > final_trunk_time_left)
04156             final_trunk_time_left = trunk_time_left;
04157       }
04158 
04159       /* No timeout was found for ringing trunks, and no timeout for the entire station */
04160       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
04161          continue;
04162 
04163       /* Compute how much time is left for a global station timeout */
04164       if (ringing_station->station->ring_timeout) {
04165          ring_timeout = ringing_station->station->ring_timeout;
04166          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
04167          time_left = (ring_timeout * 1000) - time_elapsed;
04168       }
04169 
04170       /* If the time left based on the per-trunk timeouts is smaller than the
04171        * global station ring timeout, use that. */
04172       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
04173          time_left = final_trunk_time_left;
04174 
04175       /* If there is no time left, the station needs to stop ringing */
04176       if (time_left <= 0) {
04177          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
04178          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
04179          res = 1;
04180          continue;
04181       }
04182 
04183       /* There is still some time left for this station to ring, so save that
04184        * timeout if it is the first event scheduled to occur */
04185       if (time_left < *timeout)
04186          *timeout = time_left;
04187    }
04188    AST_LIST_TRAVERSE_SAFE_END
04189 
04190    return res;
04191 }

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

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

Referenced by sla_process_timers().

04084 {
04085    struct sla_ringing_trunk *ringing_trunk;
04086    int res = 0;
04087 
04088    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04089       int time_left, time_elapsed;
04090       if (!ringing_trunk->trunk->ring_timeout)
04091          continue;
04092       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04093       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
04094       if (time_left <= 0) {
04095          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
04096          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
04097          sla_stop_ringing_trunk(ringing_trunk);
04098          res = 1;
04099          continue;
04100       }
04101       if (time_left < *timeout)
04102          *timeout = time_left;
04103    }
04104    AST_LIST_TRAVERSE_SAFE_END
04105 
04106    return res;
04107 }

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

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

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

03550 {
03551    struct sla_station *station;
03552    struct sla_trunk_ref *trunk_ref;
03553 
03554    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
03555       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03556          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
03557             || trunk_ref == exclude)
03558             continue;
03559          trunk_ref->state = state;
03560          ast_device_state_changed("SLA:%s_%s", station->name, trunk->name);
03561          break;
03562       }
03563    }
03564 }

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

Definition at line 4837 of file app_meetme.c.

References ast_strdupa, and ast_strlen_zero().

Referenced by sla_build_trunk().

04838 {
04839    char *tech, *tech_data;
04840 
04841    tech_data = ast_strdupa(device);
04842    tech = strsep(&tech_data, "/");
04843 
04844    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
04845       return -1;
04846 
04847    return 0;
04848 }

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

Referenced by sla_ring_stations().

03832 {
03833    struct sla_failed_station *failed_station;
03834    int res = 0;
03835 
03836    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
03837       if (station != failed_station->station)
03838          continue;
03839       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
03840          AST_LIST_REMOVE_CURRENT(&sla.failed_stations, entry);
03841          free(failed_station);
03842          break;
03843       }
03844       res = 1;
03845    }
03846    AST_LIST_TRAVERSE_SAFE_END
03847 
03848    return res;
03849 }

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

Check to see if a station is in use.

Definition at line 3917 of file app_meetme.c.

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

Referenced by sla_calc_station_delays(), and sla_ring_stations().

03918 {
03919    struct sla_trunk_ref *trunk_ref;
03920 
03921    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03922       if (trunk_ref->chan)
03923          return 1;
03924    }
03925 
03926    return 0;
03927 }

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

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

Referenced by sla_calc_station_delays(), and sla_ring_stations().

03817 {
03818    struct sla_ringing_station *ringing_station;
03819 
03820    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
03821       if (station == ringing_station->station)
03822          return 1;
03823    }
03824 
03825    return 0;
03826 }

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

03949 {
03950    struct sla_trunk_ref *trunk_ref;
03951    unsigned int delay = UINT_MAX;
03952    int time_left, time_elapsed;
03953 
03954    if (!ringing_trunk)
03955       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
03956    else
03957       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
03958 
03959    if (!ringing_trunk || !trunk_ref)
03960       return delay;
03961 
03962    /* If this station has a ring delay specific to the highest priority
03963     * ringing trunk, use that.  Otherwise, use the ring delay specified
03964     * globally for the station. */
03965    delay = trunk_ref->ring_delay;
03966    if (!delay)
03967       delay = station->ring_delay;
03968    if (!delay)
03969       return INT_MAX;
03970 
03971    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03972    time_left = (delay * 1000) - time_elapsed;
03973 
03974    return time_left;
03975 }

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

Definition at line 3470 of file app_meetme.c.

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

Referenced by sla_find_trunk_ref_byname().

03472 {
03473    struct sla_station_ref *station_ref;
03474    struct sla_trunk_ref *trunk_ref;
03475 
03476    /* For each station that has this call on hold, check for private hold. */
03477    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03478       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03479          if (trunk_ref->trunk != trunk || station_ref->station == station)
03480             continue;
03481          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03482             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03483             return 1;
03484          return 0;
03485       }
03486    }
03487 
03488    return 0;
03489 }

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

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

Referenced by sla_choose_ringing_trunk(), and sla_ring_stations().

03684 {
03685    struct sla_station_ref *timed_out_station;
03686 
03687    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
03688       if (station == timed_out_station->station)
03689          return 1;
03690    }
03691 
03692    return 0;
03693 }

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

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

Definition at line 4447 of file app_meetme.c.

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

Referenced by sla_station_exec().

04448 {
04449    struct sla_trunk_ref *trunk_ref = NULL;
04450 
04451    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04452       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
04453          break;
04454    }
04455 
04456    return trunk_ref;
04457 }

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

Choose the highest priority ringing trunk for a station.

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

Definition at line 3703 of file app_meetme.c.

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

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

03705 {
03706    struct sla_trunk_ref *s_trunk_ref;
03707    struct sla_ringing_trunk *ringing_trunk = NULL;
03708 
03709    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
03710       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03711          /* Make sure this is the trunk we're looking for */
03712          if (s_trunk_ref->trunk != ringing_trunk->trunk)
03713             continue;
03714 
03715          /* This trunk on the station is ringing.  But, make sure this station
03716           * didn't already time out while this trunk was ringing. */
03717          if (sla_check_timed_out_station(ringing_trunk, station))
03718             continue;
03719 
03720          if (remove)
03721             AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03722 
03723          if (trunk_ref)
03724             *trunk_ref = s_trunk_ref;
03725 
03726          break;
03727       }
03728       AST_LIST_TRAVERSE_SAFE_END
03729    
03730       if (ringing_trunk)
03731          break;
03732    }
03733 
03734    return ringing_trunk;
03735 }

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

Definition at line 3535 of file app_meetme.c.

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

Referenced by sla_ring_station().

03536 {
03537    struct sla_ringing_station *ringing_station;
03538 
03539    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
03540       return NULL;
03541 
03542    ringing_station->station = station;
03543    ringing_station->ring_begin = ast_tvnow();
03544 
03545    return ringing_station;
03546 }

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

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

03524 {
03525    struct sla_station_ref *station_ref;
03526 
03527    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
03528       return NULL;
03529 
03530    station_ref->station = station;
03531 
03532    return station_ref;
03533 }

static void sla_destroy ( void   )  [static]

Definition at line 4807 of file app_meetme.c.

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

Referenced by unload_module().

04808 {
04809    struct sla_trunk *trunk;
04810    struct sla_station *station;
04811 
04812    AST_RWLIST_WRLOCK(&sla_trunks);
04813    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
04814       destroy_trunk(trunk);
04815    AST_RWLIST_UNLOCK(&sla_trunks);
04816 
04817    AST_RWLIST_WRLOCK(&sla_stations);
04818    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
04819       destroy_station(station);
04820    AST_RWLIST_UNLOCK(&sla_stations);
04821 
04822    if (sla.thread != AST_PTHREADT_NULL) {
04823       ast_mutex_lock(&sla.lock);
04824       sla.stop = 1;
04825       ast_cond_signal(&sla.cond);
04826       ast_mutex_unlock(&sla.lock);
04827       pthread_join(sla.thread, NULL);
04828    }
04829 
04830    /* Drop any created contexts from the dialplan */
04831    ast_context_destroy(NULL, sla_registrar);
04832 
04833    ast_mutex_destroy(&sla.lock);
04834    ast_cond_destroy(&sla.cond);
04835 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 3674 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

03675 {
03676    sla_queue_event(SLA_EVENT_DIAL_STATE);
03677 }

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

Find an SLA station by name.

Note:
This must be called with the sla_stations container locked

Definition at line 3458 of file app_meetme.c.

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

Referenced by sla_station_exec().

03459 {
03460    struct sla_station *station = NULL;
03461 
03462    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03463       if (!strcasecmp(station->name, name))
03464          break;
03465    }
03466 
03467    return station;
03468 }

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

Find an SLA trunk by name.

Note:
This must be called with the sla_trunks container locked

Definition at line 3443 of file app_meetme.c.

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

Referenced by sla_trunk_exec().

03444 {
03445    struct sla_trunk *trunk = NULL;
03446 
03447    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03448       if (!strcasecmp(trunk->name, name))
03449          break;
03450    }
03451 
03452    return trunk;
03453 }

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

Definition at line 3929 of file app_meetme.c.

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

Referenced by sla_check_station_delay().

03931 {
03932    struct sla_trunk_ref *trunk_ref = NULL;
03933 
03934    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03935       if (trunk_ref->trunk == trunk)
03936          break;
03937    }
03938 
03939    return trunk_ref;
03940 }

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

Find a trunk reference on a station by name.

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

Definition at line 3498 of file app_meetme.c.

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

Referenced by sla_station_exec().

03500 {
03501    struct sla_trunk_ref *trunk_ref = NULL;
03502 
03503    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03504       if (strcasecmp(trunk_ref->trunk->name, name))
03505          continue;
03506 
03507       if ( (trunk_ref->trunk->barge_disabled 
03508          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
03509          (trunk_ref->trunk->hold_stations 
03510          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
03511          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
03512          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
03513       {
03514          trunk_ref = NULL;
03515       }
03516 
03517       break;
03518    }
03519 
03520    return trunk_ref;
03521 }

static void sla_handle_dial_state_event ( void   )  [static]

Definition at line 3737 of file app_meetme.c.

References ALL_TRUNK_REFS, answer_trunk_chan(), ast_cond_destroy(), ast_cond_init(), ast_cond_wait(), 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_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, sla_trunk::chan, sla_trunk_ref::chan, run_station_args::cond, cond, run_station_args::cond_lock, sla_station::dial, announce_listitem::entry, free, LOG_DEBUG, 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().

03738 {
03739    struct sla_ringing_station *ringing_station;
03740 
03741    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03742       struct sla_trunk_ref *s_trunk_ref = NULL;
03743       struct sla_ringing_trunk *ringing_trunk = NULL;
03744       struct run_station_args args;
03745       enum ast_dial_result dial_res;
03746       pthread_attr_t attr;
03747       pthread_t dont_care;
03748       ast_mutex_t cond_lock;
03749       ast_cond_t cond;
03750 
03751       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
03752       case AST_DIAL_RESULT_HANGUP:
03753       case AST_DIAL_RESULT_INVALID:
03754       case AST_DIAL_RESULT_FAILED:
03755       case AST_DIAL_RESULT_TIMEOUT:
03756       case AST_DIAL_RESULT_UNANSWERED:
03757          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03758          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
03759          break;
03760       case AST_DIAL_RESULT_ANSWERED:
03761          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03762          /* Find the appropriate trunk to answer. */
03763          ast_mutex_lock(&sla.lock);
03764          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
03765          ast_mutex_unlock(&sla.lock);
03766          if (!ringing_trunk) {
03767             ast_log(LOG_DEBUG, "Found no ringing trunk for station '%s' to answer!\n",
03768                ringing_station->station->name);
03769             break;
03770          }
03771          /* Track the channel that answered this trunk */
03772          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
03773          /* Actually answer the trunk */
03774          answer_trunk_chan(ringing_trunk->trunk->chan);
03775          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
03776          /* Now, start a thread that will connect this station to the trunk.  The rest of
03777           * the code here sets up the thread and ensures that it is able to save the arguments
03778           * before they are no longer valid since they are allocated on the stack. */
03779          args.trunk_ref = s_trunk_ref;
03780          args.station = ringing_station->station;
03781          args.cond = &cond;
03782          args.cond_lock = &cond_lock;
03783          free(ringing_trunk);
03784          free(ringing_station);
03785          ast_mutex_init(&cond_lock);
03786          ast_cond_init(&cond, NULL);
03787          pthread_attr_init(&attr);
03788          pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
03789          ast_mutex_lock(&cond_lock);
03790          ast_pthread_create_background(&dont_care, &attr, run_station, &args);
03791          ast_cond_wait(&cond, &cond_lock);
03792          ast_mutex_unlock(&cond_lock);
03793          ast_mutex_destroy(&cond_lock);
03794          ast_cond_destroy(&cond);
03795          pthread_attr_destroy(&attr);
03796          break;
03797       case AST_DIAL_RESULT_TRYING:
03798       case AST_DIAL_RESULT_RINGING:
03799       case AST_DIAL_RESULT_PROGRESS:
03800       case AST_DIAL_RESULT_PROCEEDING:
03801          break;
03802       }
03803       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
03804          /* Queue up reprocessing ringing trunks, and then ringing stations again */
03805          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
03806          sla_queue_event(SLA_EVENT_DIAL_STATE);
03807          break;
03808       }
03809    }
03810    AST_LIST_TRAVERSE_SAFE_END
03811 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 4059 of file app_meetme.c.

References sla_trunk::active_stations, ast_atomic_fetchadd_int(), AST_CONTROL_HOLD, ast_device_state_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_trunk::on_hold, sla_change_trunk_state(), SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, sla_trunk_ref::state, sla_event::station, sla_trunk_ref::trunk, and sla_event::trunk_ref.

Referenced by sla_thread().

04060 {
04061    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
04062    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
04063    ast_device_state_changed("SLA:%s_%s", 
04064       event->station->name, event->trunk_ref->trunk->name);
04065    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
04066       INACTIVE_TRUNK_REFS, event->trunk_ref);
04067 
04068    if (event->trunk_ref->trunk->active_stations == 1) {
04069       /* The station putting it on hold is the only one on the call, so start
04070        * Music on hold to the trunk. */
04071       event->trunk_ref->trunk->on_hold = 1;
04072       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
04073    }
04074 
04075    ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
04076    event->trunk_ref->chan = NULL;
04077 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 4049 of file app_meetme.c.

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

Referenced by sla_thread().

04050 {
04051    ast_mutex_lock(&sla.lock);
04052    sla_ring_stations();
04053    ast_mutex_unlock(&sla.lock);
04054 
04055    /* Find stations that shouldn't be ringing anymore. */
04056    sla_hangup_stations();
04057 }

static void sla_hangup_stations ( void   )  [static]

Definition at line 4021 of file app_meetme.c.

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

Referenced by sla_handle_ringing_trunk_event().

04022 {
04023    struct sla_trunk_ref *trunk_ref;
04024    struct sla_ringing_station *ringing_station;
04025 
04026    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04027       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04028          struct sla_ringing_trunk *ringing_trunk;
04029          ast_mutex_lock(&sla.lock);
04030          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04031             if (trunk_ref->trunk == ringing_trunk->trunk)
04032                break;
04033          }
04034          ast_mutex_unlock(&sla.lock);
04035          if (ringing_trunk)
04036             break;
04037       }
04038       if (!trunk_ref) {
04039          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
04040          ast_dial_join(ringing_station->station->dial);
04041          ast_dial_destroy(ringing_station->station->dial);
04042          ringing_station->station->dial = NULL;
04043          free(ringing_station);
04044       }
04045    }
04046    AST_LIST_TRAVERSE_SAFE_END
04047 }

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

Definition at line 1120 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01121 {
01122    const char *hold = "Unknown";
01123 
01124    switch (hold_access) {
01125    case SLA_HOLD_OPEN:
01126       hold = "Open";
01127       break;
01128    case SLA_HOLD_PRIVATE:
01129       hold = "Private";
01130    default:
01131       break;
01132    }
01133 
01134    return hold;
01135 }

static int sla_load_config ( void   )  [static]

Definition at line 5093 of file app_meetme.c.

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

Referenced by load_config().

05094 {
05095    struct ast_config *cfg;
05096    const char *cat = NULL;
05097    int res = 0;
05098    const char *val;
05099 
05100    ast_mutex_init(&sla.lock);
05101    ast_cond_init(&sla.cond, NULL);
05102 
05103    if (!(cfg = ast_config_load(SLA_CONFIG_FILE)))
05104       return 0; /* Treat no config as normal */
05105 
05106    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
05107       sla.attempt_callerid = ast_true(val);
05108 
05109    while ((cat = ast_category_browse(cfg, cat)) && !res) {
05110       const char *type;
05111       if (!strcasecmp(cat, "general"))
05112          continue;
05113       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
05114          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
05115             SLA_CONFIG_FILE);
05116          continue;
05117       }
05118       if (!strcasecmp(type, "trunk"))
05119          res = sla_build_trunk(cfg, cat);
05120       else if (!strcasecmp(type, "station"))
05121          res = sla_build_station(cfg, cat);
05122       else {
05123          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
05124             SLA_CONFIG_FILE, type);
05125       }
05126    }
05127 
05128    ast_config_destroy(cfg);
05129 
05130    if (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations))
05131       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
05132 
05133    return res;
05134 }

static int sla_process_timers ( struct timespec *  ts  )  [static]

Calculate the time until the next known event.

Note:
Called with sla.lock locked

Definition at line 4237 of file app_meetme.c.

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

Referenced by sla_thread().

04238 {
04239    unsigned int timeout = UINT_MAX;
04240    struct timeval tv;
04241    unsigned int change_made = 0;
04242 
04243    /* Check for ring timeouts on ringing trunks */
04244    if (sla_calc_trunk_timeouts(&timeout))
04245       change_made = 1;
04246 
04247    /* Check for ring timeouts on ringing stations */
04248    if (sla_calc_station_timeouts(&timeout))
04249       change_made = 1;
04250 
04251    /* Check for station ring delays */
04252    if (sla_calc_station_delays(&timeout))
04253       change_made = 1;
04254 
04255    /* queue reprocessing of ringing trunks */
04256    if (change_made)
04257       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
04258 
04259    /* No timeout */
04260    if (timeout == UINT_MAX)
04261       return 0;
04262 
04263    if (ts) {
04264       tv = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
04265       ts->tv_sec = tv.tv_sec;
04266       ts->tv_nsec = tv.tv_usec * 1000;
04267    }
04268 
04269    return 1;
04270 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

Definition at line 1423 of file app_meetme.c.

References sla_queue_event_full().

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

01424 {
01425    sla_queue_event_full(type, NULL, NULL, 1);
01426 }

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

Queue a SLA event from the conference.

Definition at line 1429 of file app_meetme.c.

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

Referenced by conf_run().

01431 {
01432    struct sla_station *station;
01433    struct sla_trunk_ref *trunk_ref = NULL;
01434    char *trunk_name;
01435 
01436    trunk_name = ast_strdupa(conf->confno);
01437    strsep(&trunk_name, "_");
01438    if (ast_strlen_zero(trunk_name)) {
01439       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01440       return;
01441    }
01442 
01443    AST_RWLIST_RDLOCK(&sla_stations);
01444    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01445       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01446          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01447             break;
01448       }
01449       if (trunk_ref)
01450          break;
01451    }
01452    AST_RWLIST_UNLOCK(&sla_stations);
01453 
01454    if (!trunk_ref) {
01455       ast_log(LOG_DEBUG, "Trunk not found for event!\n");
01456       return;
01457    }
01458 
01459    sla_queue_event_full(type, trunk_ref, station, 1);
01460 }

static void sla_queue_event_full ( enum sla_event_type  type,
struct sla_trunk_ref trunk_ref,
struct sla_station station,
int  lock 
) [static]

Definition at line 1391 of file app_meetme.c.

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

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

01393 {
01394    struct sla_event *event;
01395 
01396    if (sla.thread == AST_PTHREADT_NULL) {
01397       return;
01398    }
01399 
01400    if (!(event = ast_calloc(1, sizeof(*event))))
01401       return;
01402 
01403    event->type = type;
01404    event->trunk_ref = trunk_ref;
01405    event->station = station;
01406 
01407    if (!lock) {
01408       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01409       return;
01410    }
01411 
01412    ast_mutex_lock(&sla.lock);
01413    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01414    ast_cond_signal(&sla.cond);
01415    ast_mutex_unlock(&sla.lock);
01416 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1418 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01419 {
01420    sla_queue_event_full(type, NULL, NULL, 0);
01421 }

static int sla_ring_station ( struct sla_ringing_trunk ringing_trunk,
struct sla_station station 
) [static]

Ring a station.

Note:
Assumes sla.lock is locked

Definition at line 3854 of file app_meetme.c.

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

Referenced by sla_ring_stations().

03855 {
03856    char *tech, *tech_data;
03857    struct ast_dial *dial;
03858    struct sla_ringing_station *ringing_station;
03859    const char *cid_name = NULL, *cid_num = NULL;
03860    enum ast_dial_result res;
03861 
03862    if (!(dial = ast_dial_create()))
03863       return -1;
03864 
03865    ast_dial_set_state_callback(dial, sla_dial_state_callback);
03866    tech_data = ast_strdupa(station->device);
03867    tech = strsep(&tech_data, "/");
03868 
03869    if (ast_dial_append(dial, tech, tech_data) == -1) {
03870       ast_dial_destroy(dial);
03871       return -1;
03872    }
03873 
03874    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
03875       cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
03876       free(ringing_trunk->trunk->chan->cid.cid_name);
03877       ringing_trunk->trunk->chan->cid.cid_name = NULL;
03878    }
03879    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
03880       cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
03881       free(ringing_trunk->trunk->chan->cid.cid_num);
03882       ringing_trunk->trunk->chan->cid.cid_num = NULL;
03883    }
03884 
03885    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
03886    
03887    if (cid_name)
03888       ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
03889    if (cid_num)
03890       ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
03891    
03892    if (res != AST_DIAL_RESULT_TRYING) {
03893       struct sla_failed_station *failed_station;
03894       ast_dial_destroy(dial);
03895       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
03896          return -1;
03897       failed_station->station = station;
03898       failed_station->last_try = ast_tvnow();
03899       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
03900       return -1;
03901    }
03902    if (!(ringing_station = sla_create_ringing_station(station))) {
03903       ast_dial_join(dial);
03904       ast_dial_destroy(dial);
03905       return -1;
03906    }
03907 
03908    station->dial = dial;
03909 
03910    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
03911 
03912    return 0;
03913 }

static void sla_ring_stations ( void   )  [static]

Ring stations based on current set of ringing trunks.

Note:
Assumes that sla.lock is locked

Definition at line 3980 of file app_meetme.c.

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

Referenced by sla_handle_ringing_trunk_event().

03981 {
03982    struct sla_station_ref *station_ref;
03983    struct sla_ringing_trunk *ringing_trunk;
03984 
03985    /* Make sure that every station that uses at least one of the ringing
03986     * trunks, is ringing. */
03987    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03988       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
03989          int time_left;
03990 
03991          /* Is this station already ringing? */
03992          if (sla_check_ringing_station(station_ref->station))
03993             continue;
03994 
03995          /* Is this station already in a call? */
03996          if (sla_check_inuse_station(station_ref->station))
03997             continue;
03998 
03999          /* Did we fail to dial this station earlier?  If so, has it been
04000           * a minute since we tried? */
04001          if (sla_check_failed_station(station_ref->station))
04002             continue;
04003 
04004          /* If this station already timed out while this trunk was ringing,
04005           * do not dial it again for this ringing trunk. */
04006          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
04007             continue;
04008 
04009          /* Check for a ring delay in progress */
04010          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
04011          if (time_left != INT_MAX && time_left > 0)
04012             continue;
04013 
04014          /* It is time to make this station begin to ring.  Do it! */
04015          sla_ring_station(ringing_trunk, station_ref->station);
04016       }
04017    }
04018    /* Now, all of the stations that should be ringing, are ringing. */
04019 }

static int sla_show_stations ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 1197 of file app_meetme.c.

References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, sla_station::autocontext, sla_station::device, announce_listitem::entry, sla_station::hold_access, sla_trunk::name, sla_station::name, RESULT_SUCCESS, sla_trunk_ref::ring_delay, sla_station::ring_delay, sla_trunk_ref::ring_timeout, sla_station::ring_timeout, S_OR, sla_hold_str(), sla_trunk_ref::state, sla_trunk_ref::trunk, sla_station::trunks, and trunkstate2str().

01198 {
01199    const struct sla_station *station;
01200 
01201    ast_cli(fd, "\n" 
01202                "=============================================================\n"
01203                "=== Configured SLA Stations =================================\n"
01204                "=============================================================\n"
01205                "===\n");
01206    AST_RWLIST_RDLOCK(&sla_stations);
01207    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01208       struct sla_trunk_ref *trunk_ref;
01209       char ring_timeout[16] = "(none)";
01210       char ring_delay[16] = "(none)";
01211       if (station->ring_timeout) {
01212          snprintf(ring_timeout, sizeof(ring_timeout), 
01213             "%u", station->ring_timeout);
01214       }
01215       if (station->ring_delay) {
01216          snprintf(ring_delay, sizeof(ring_delay), 
01217             "%u", station->ring_delay);
01218       }
01219       ast_cli(fd, "=== ---------------------------------------------------------\n"
01220                   "=== Station Name:    %s\n"
01221                   "=== ==> Device:      %s\n"
01222                   "=== ==> AutoContext: %s\n"
01223                   "=== ==> RingTimeout: %s\n"
01224                   "=== ==> RingDelay:   %s\n"
01225                   "=== ==> HoldAccess:  %s\n"
01226                   "=== ==> Trunks ...\n",
01227                   station->name, station->device,
01228                   S_OR(station->autocontext, "(none)"), 
01229                   ring_timeout, ring_delay,
01230                   sla_hold_str(station->hold_access));
01231       AST_RWLIST_RDLOCK(&sla_trunks);
01232       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01233          if (trunk_ref->ring_timeout) {
01234             snprintf(ring_timeout, sizeof(ring_timeout),
01235                "%u", trunk_ref->ring_timeout);
01236          } else
01237             strcpy(ring_timeout, "(none)");
01238          if (trunk_ref->ring_delay) {
01239             snprintf(ring_delay, sizeof(ring_delay),
01240                "%u", trunk_ref->ring_delay);
01241          } else
01242             strcpy(ring_delay, "(none)");
01243          ast_cli(fd, "===    ==> Trunk Name: %s\n"
01244                      "===       ==> State:       %s\n"
01245                      "===       ==> RingTimeout: %s\n"
01246                      "===       ==> RingDelay:   %s\n",
01247                      trunk_ref->trunk->name,
01248                      trunkstate2str(trunk_ref->state),
01249                      ring_timeout, ring_delay);
01250       }
01251       AST_RWLIST_UNLOCK(&sla_trunks);
01252       ast_cli(fd, "=== ---------------------------------------------------------\n"
01253                   "===\n");
01254    }
01255    AST_RWLIST_UNLOCK(&sla_stations);
01256    ast_cli(fd, "============================================================\n"
01257                "\n");
01258 
01259    return RESULT_SUCCESS;
01260 }

static int sla_show_trunks ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 1137 of file app_meetme.c.

References ast_cli(), AST_LIST_TRAVERSE, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, sla_trunk::autocontext, sla_trunk::barge_disabled, sla_trunk::device, announce_listitem::entry, sla_trunk::hold_access, sla_station::name, sla_trunk::name, RESULT_SUCCESS, sla_trunk::ring_timeout, S_OR, sla_hold_str(), sla_station_ref::station, and sla_trunk::stations.

01138 {
01139    const struct sla_trunk *trunk;
01140 
01141    ast_cli(fd, "\n"
01142                "=============================================================\n"
01143                "=== Configured SLA Trunks ===================================\n"
01144                "=============================================================\n"
01145                "===\n");
01146    AST_RWLIST_RDLOCK(&sla_trunks);
01147    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01148       struct sla_station_ref *station_ref;
01149       char ring_timeout[16] = "(none)";
01150       if (trunk->ring_timeout)
01151          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01152       ast_cli(fd, "=== ---------------------------------------------------------\n"
01153                   "=== Trunk Name:       %s\n"
01154                   "=== ==> Device:       %s\n"
01155                   "=== ==> AutoContext:  %s\n"
01156                   "=== ==> RingTimeout:  %s\n"
01157                   "=== ==> BargeAllowed: %s\n"
01158                   "=== ==> HoldAccess:   %s\n"
01159                   "=== ==> Stations ...\n",
01160                   trunk->name, trunk->device, 
01161                   S_OR(trunk->autocontext, "(none)"), 
01162                   ring_timeout,
01163                   trunk->barge_disabled ? "No" : "Yes",
01164                   sla_hold_str(trunk->hold_access));
01165       AST_RWLIST_RDLOCK(&sla_stations);
01166       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01167          ast_cli(fd, "===    ==> Station name: %s\n", station_ref->station->name);
01168       AST_RWLIST_UNLOCK(&sla_stations);
01169       ast_cli(fd, "=== ---------------------------------------------------------\n"
01170                   "===\n");
01171    }
01172    AST_RWLIST_UNLOCK(&sla_trunks);
01173    ast_cli(fd, "=============================================================\n"
01174                "\n");
01175 
01176    return RESULT_SUCCESS;
01177 }

static int sla_state ( const char *  data  )  [static]

Definition at line 4717 of file app_meetme.c.

References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_ONHOLD, AST_DEVICE_RINGING, AST_LIST_TRAVERSE, ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_strdupa, announce_listitem::entry, LOG_ERROR, sla_trunk::name, sla_station::name, SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, SLA_TRUNK_STATE_UP, sla_trunk_ref::state, sla_trunk_ref::trunk, and sla_station::trunks.

Referenced by load_module().

04718 {
04719    char *buf, *station_name, *trunk_name;
04720    struct sla_station *station;
04721    struct sla_trunk_ref *trunk_ref;
04722    int res = AST_DEVICE_INVALID;
04723 
04724    trunk_name = buf = ast_strdupa(data);
04725    station_name = strsep(&trunk_name, "_");
04726 
04727    AST_RWLIST_RDLOCK(&sla_stations);
04728    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04729       if (strcasecmp(station_name, station->name))
04730          continue;
04731       AST_RWLIST_RDLOCK(&sla_trunks);
04732       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04733          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
04734             break;
04735       }
04736       if (!trunk_ref) {
04737          AST_RWLIST_UNLOCK(&sla_trunks);
04738          break;
04739       }
04740       switch (trunk_ref->state) {
04741       case SLA_TRUNK_STATE_IDLE:
04742          res = AST_DEVICE_NOT_INUSE;
04743          break;
04744       case SLA_TRUNK_STATE_RINGING:
04745          res = AST_DEVICE_RINGING;
04746          break;
04747       case SLA_TRUNK_STATE_UP:
04748          res = AST_DEVICE_INUSE;
04749          break;
04750       case SLA_TRUNK_STATE_ONHOLD:
04751       case SLA_TRUNK_STATE_ONHOLD_BYME:
04752          res = AST_DEVICE_ONHOLD;
04753          break;
04754       }
04755       AST_RWLIST_UNLOCK(&sla_trunks);
04756    }
04757    AST_RWLIST_UNLOCK(&sla_stations);
04758 
04759    if (res == AST_DEVICE_INVALID) {
04760       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
04761          trunk_name, station_name);
04762    }
04763 
04764    return res;
04765 }

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

Definition at line 4459 of file app_meetme.c.

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

Referenced by load_module().

04460 {
04461    char *station_name, *trunk_name;
04462    struct sla_station *station;
04463    struct sla_trunk_ref *trunk_ref = NULL;
04464    char conf_name[MAX_CONFNUM];
04465    struct ast_flags conf_flags = { 0 };
04466    struct ast_conference *conf;
04467 
04468    if (ast_strlen_zero(data)) {
04469       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04470       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04471       return 0;
04472    }
04473 
04474    trunk_name = ast_strdupa(data);
04475    station_name = strsep(&trunk_name, "_");
04476 
04477    if (ast_strlen_zero(station_name)) {
04478       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04479       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04480       return 0;
04481    }
04482 
04483    AST_RWLIST_RDLOCK(&sla_stations);
04484    station = sla_find_station(station_name);
04485    AST_RWLIST_UNLOCK(&sla_stations);
04486 
04487    if (!station) {
04488       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
04489       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04490       return 0;
04491    }
04492 
04493    AST_RWLIST_RDLOCK(&sla_trunks);
04494    if (!ast_strlen_zero(trunk_name)) {
04495       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
04496    } else
04497       trunk_ref = sla_choose_idle_trunk(station);
04498    AST_RWLIST_UNLOCK(&sla_trunks);
04499 
04500    if (!trunk_ref) {
04501       if (ast_strlen_zero(trunk_name))
04502          ast_log(LOG_NOTICE, "No trunks available for call.\n");
04503       else {
04504          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
04505             "'%s' due to access controls.\n", trunk_name);
04506       }
04507       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
04508       return 0;
04509    }
04510 
04511    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
04512       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
04513          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04514       else {
04515          trunk_ref->state = SLA_TRUNK_STATE_UP;
04516          ast_device_state_changed("SLA:%s_%s", station->name, trunk_ref->trunk->name);
04517       }
04518    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
04519       struct sla_ringing_trunk *ringing_trunk;
04520 
04521       ast_mutex_lock(&sla.lock);
04522       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04523          if (ringing_trunk->trunk == trunk_ref->trunk) {
04524             AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
04525             break;
04526          }
04527       }
04528       AST_LIST_TRAVERSE_SAFE_END
04529       ast_mutex_unlock(&sla.lock);
04530 
04531       if (ringing_trunk) {
04532          answer_trunk_chan(ringing_trunk->trunk->chan);
04533          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04534 
04535          free(ringing_trunk);
04536 
04537          /* Queue up reprocessing ringing trunks, and then ringing stations again */
04538          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04539          sla_queue_event(SLA_EVENT_DIAL_STATE);
04540       }
04541    }
04542 
04543    trunk_ref->chan = chan;
04544 
04545    if (!trunk_ref->trunk->chan) {
04546       ast_mutex_t cond_lock;
04547       ast_cond_t cond;
04548       pthread_t dont_care;
04549       pthread_attr_t attr;
04550       struct dial_trunk_args args = {
04551          .trunk_ref = trunk_ref,
04552          .station = station,
04553          .cond_lock = &cond_lock,
04554          .cond = &cond,
04555       };
04556       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04557       /* Create a thread to dial the trunk and dump it into the conference.
04558        * However, we want to wait until the trunk has been dialed and the
04559        * conference is created before continuing on here. */
04560       ast_autoservice_start(chan);
04561       ast_mutex_init(&cond_lock);
04562       ast_cond_init(&cond, NULL);
04563       pthread_attr_init(&attr);
04564       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04565       ast_mutex_lock(&cond_lock);
04566       ast_pthread_create_background(&dont_care, &attr, dial_trunk, &args);
04567       ast_cond_wait(&cond, &cond_lock);
04568       ast_mutex_unlock(&cond_lock);
04569       ast_mutex_destroy(&cond_lock);
04570       ast_cond_destroy(&cond);
04571       pthread_attr_destroy(&attr);
04572       ast_autoservice_stop(chan);
04573       if (!trunk_ref->trunk->chan) {
04574          ast_log(LOG_DEBUG, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
04575          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
04576          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04577          trunk_ref->chan = NULL;
04578          return 0;
04579       }
04580    }
04581 
04582    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
04583       trunk_ref->trunk->on_hold) {
04584       trunk_ref->trunk->on_hold = 0;
04585       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
04586       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04587    }
04588 
04589    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04590    ast_set_flag(&conf_flags, 
04591       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04592    ast_answer(chan);
04593    conf = build_conf(conf_name, "", "", 0, 0, 1);
04594    if (conf) {
04595       conf_run(chan, conf, conf_flags.flags, NULL);
04596       dispose_conf(conf);
04597       conf = NULL;
04598    }
04599    trunk_ref->chan = NULL;
04600    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04601       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04602       strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
04603       admin_exec(NULL, conf_name);
04604       trunk_ref->trunk->hold_stations = 0;
04605       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04606    }
04607    
04608    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
04609 
04610    return 0;
04611 }

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

Definition at line 3639 of file app_meetme.c.

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

Referenced by sla_calc_station_timeouts(), and sla_handle_dial_state_event().

03641 {
03642    struct sla_ringing_trunk *ringing_trunk;
03643    struct sla_trunk_ref *trunk_ref;
03644    struct sla_station_ref *station_ref;
03645 
03646    ast_dial_join(ringing_station->station->dial);
03647    ast_dial_destroy(ringing_station->station->dial);
03648    ringing_station->station->dial = NULL;
03649 
03650    if (hangup == SLA_STATION_HANGUP_NORMAL)
03651       goto done;
03652 
03653    /* If the station is being hung up because of a timeout, then add it to the
03654     * list of timed out stations on each of the ringing trunks.  This is so
03655     * that when doing further processing to figure out which stations should be
03656     * ringing, which trunk to answer, determining timeouts, etc., we know which
03657     * ringing trunks we should ignore. */
03658    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03659       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03660          if (ringing_trunk->trunk == trunk_ref->trunk)
03661             break;
03662       }
03663       if (!trunk_ref)
03664          continue;
03665       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
03666          continue;
03667       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
03668    }
03669 
03670 done:
03671    free(ringing_station);
03672 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

Definition at line 3624 of file app_meetme.c.

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

Referenced by sla_calc_trunk_timeouts().

03625 {
03626    char buf[80];
03627    struct sla_station_ref *station_ref;
03628 
03629    snprintf(buf, sizeof(buf), "SLA_%s|K", ringing_trunk->trunk->name);
03630    admin_exec(NULL, buf);
03631    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03632 
03633    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
03634       free(station_ref);
03635 
03636    free(ringing_trunk);
03637 }

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

Definition at line 4272 of file app_meetme.c.

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

Referenced by sla_load_config().

04273 {
04274    struct sla_failed_station *failed_station;
04275    struct sla_ringing_station *ringing_station;
04276 
04277    ast_mutex_lock(&sla.lock);
04278 
04279    while (!sla.stop) {
04280       struct sla_event *event;
04281       struct timespec ts = { 0, };
04282       unsigned int have_timeout = 0;
04283 
04284       if (AST_LIST_EMPTY(&sla.event_q)) {
04285          if ((have_timeout = sla_process_timers(&ts)))
04286             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
04287          else
04288             ast_cond_wait(&sla.cond, &sla.lock);
04289          if (sla.stop)
04290             break;
04291       }
04292 
04293       if (have_timeout)
04294          sla_process_timers(NULL);
04295 
04296       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
04297          ast_mutex_unlock(&sla.lock);
04298          switch (event->type) {
04299          case SLA_EVENT_HOLD:
04300             sla_handle_hold_event(event);
04301             break;
04302          case SLA_EVENT_DIAL_STATE:
04303             sla_handle_dial_state_event();
04304             break;
04305          case SLA_EVENT_RINGING_TRUNK:
04306             sla_handle_ringing_trunk_event();
04307             break;
04308          }
04309          free(event);
04310          ast_mutex_lock(&sla.lock);
04311       }
04312    }
04313 
04314    ast_mutex_unlock(&sla.lock);
04315 
04316    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
04317       free(ringing_station);
04318 
04319    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
04320       free(failed_station);
04321 
04322    return NULL;
04323 }

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

Definition at line 4646 of file app_meetme.c.

References ALL_TRUNK_REFS, AST_CONTROL_RINGING, ast_indicate(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_set_flag, build_conf(), sla_trunk::chan, conf_run(), CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_PASS_DTMF, dispose_conf(), announce_listitem::entry, ast_flags::flags, free, LOG_ERROR, MAX_CONFNUM, sla_trunk::on_hold, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), queue_ringing_trunk(), sla, sla_change_trunk_state(), SLA_EVENT_RINGING_TRUNK, sla_find_trunk(), sla_queue_event(), SLA_TRUNK_STATE_IDLE, and sla_ringing_trunk::trunk.

Referenced by load_module().

04647 {
04648    const char *trunk_name = data;
04649    char conf_name[MAX_CONFNUM];
04650    struct ast_conference *conf;
04651    struct ast_flags conf_flags = { 0 };
04652    struct sla_trunk *trunk;
04653    struct sla_ringing_trunk *ringing_trunk;
04654 
04655    AST_RWLIST_RDLOCK(&sla_trunks);
04656    trunk = sla_find_trunk(trunk_name);
04657    AST_RWLIST_UNLOCK(&sla_trunks);
04658    if (!trunk) {
04659       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", trunk_name);
04660       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04661       return 0;
04662    }
04663    if (trunk->chan) {
04664       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
04665          trunk_name);
04666       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04667       return 0;
04668    }
04669    trunk->chan = chan;
04670 
04671    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
04672       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04673       return 0;
04674    }
04675 
04676    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_name);
04677    conf = build_conf(conf_name, "", "", 1, 1, 1);
04678    if (!conf) {
04679       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04680       return 0;
04681    }
04682    ast_set_flag(&conf_flags, 
04683       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
04684    ast_indicate(chan, AST_CONTROL_RINGING);
04685    conf_run(chan, conf, conf_flags.flags, NULL);
04686    dispose_conf(conf);
04687    conf = NULL;
04688    trunk->chan = NULL;
04689    trunk->on_hold = 0;
04690 
04691    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04692 
04693    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
04694       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
04695 
04696    /* Remove the entry from the list of ringing trunks if it is still there. */
04697    ast_mutex_lock(&sla.lock);
04698    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04699       if (ringing_trunk->trunk == trunk) {
04700          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
04701          break;
04702       }
04703    }
04704    AST_LIST_TRAVERSE_SAFE_END
04705    ast_mutex_unlock(&sla.lock);
04706    if (ringing_trunk) {
04707       free(ringing_trunk);
04708       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
04709       /* Queue reprocessing of ringing trunks to make stations stop ringing
04710        * that shouldn't be ringing after this trunk stopped. */
04711       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04712    }
04713 
04714    return 0;
04715 }

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

Definition at line 1179 of file app_meetme.c.

References S, SLA_TRUNK_STATE_IDLE, SLA_TRUNK_STATE_ONHOLD, SLA_TRUNK_STATE_ONHOLD_BYME, SLA_TRUNK_STATE_RINGING, and SLA_TRUNK_STATE_UP.

Referenced by sla_show_stations().

01180 {
01181 #define S(e) case e: return # e;
01182    switch (state) {
01183    S(SLA_TRUNK_STATE_IDLE)
01184    S(SLA_TRUNK_STATE_RINGING)
01185    S(SLA_TRUNK_STATE_UP)
01186    S(SLA_TRUNK_STATE_ONHOLD)
01187    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01188    }
01189    return "Uknown State";
01190 #undef S
01191 }

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

Definition at line 707 of file app_meetme.c.

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

Referenced by admin_exec(), conf_run(), user_listen_voldown_cb(), and user_listen_volup_cb().

00708 {
00709    tweak_volume(&user->listen, action);
00710    /* attempt to make the adjustment in the channel driver;
00711       if successful, don't adjust in the frame reading routine
00712    */
00713    if (!set_listen_volume(user, user->listen.desired))
00714       user->listen.actual = 0;
00715    else
00716       user->listen.actual = user->listen.desired;
00717 }

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

Definition at line 695 of file app_meetme.c.

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

Referenced by admin_exec(), conf_run(), user_talk_voldown_cb(), and user_talk_volup_cb().

00696 {
00697    tweak_volume(&user->talk, action);
00698    /* attempt to make the adjustment in the channel driver;
00699       if successful, don't adjust in the frame reading routine
00700    */
00701    if (!set_talk_volume(user, user->talk.desired))
00702       user->talk.actual = 0;
00703    else
00704       user->talk.actual = user->talk.desired;
00705 }

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

Definition at line 660 of file app_meetme.c.

References volume::desired, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

00661 {
00662    switch (action) {
00663    case VOL_UP:
00664       switch (vol->desired) { 
00665       case 5:
00666          break;
00667       case 0:
00668          vol->desired = 2;
00669          break;
00670       case -2:
00671          vol->desired = 0;
00672          break;
00673       default:
00674          vol->desired++;
00675          break;
00676       }
00677       break;
00678    case VOL_DOWN:
00679       switch (vol->desired) {
00680       case -5:
00681          break;
00682       case 2:
00683          vol->desired = 0;
00684          break;
00685       case 0:
00686          vol->desired = -2;
00687          break;
00688       default:
00689          vol->desired--;
00690          break;
00691       }
00692    }
00693 }

static int unload_module ( void   )  [static]

Definition at line 5147 of file app_meetme.c.

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

05148 {
05149    int res = 0;
05150    
05151    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05152    res = ast_manager_unregister("MeetmeMute");
05153    res |= ast_manager_unregister("MeetmeUnmute");
05154    res |= ast_unregister_application(app3);
05155    res |= ast_unregister_application(app2);
05156    res |= ast_unregister_application(app);
05157    res |= ast_unregister_application(slastation_app);
05158    res |= ast_unregister_application(slatrunk_app);
05159 
05160    ast_devstate_prov_del("Meetme");
05161    ast_devstate_prov_del("SLA");
05162 
05163    ast_module_user_hangup_all();
05164    
05165    sla_destroy();
05166 
05167    return res;
05168 }

static int user_listen_voldown_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 3093 of file app_meetme.c.

References tweak_listen_volume().

Referenced by admin_exec().

03094 {
03095    struct ast_conf_user *user = obj;
03096    tweak_listen_volume(user, VOL_DOWN);
03097    return 0;
03098 }

static int user_listen_volup_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 3086 of file app_meetme.c.

References tweak_listen_volume(), and VOL_UP.

Referenced by admin_exec().

03087 {
03088    struct ast_conf_user *user = obj;
03089    tweak_listen_volume(user, VOL_UP);
03090    return 0;
03091 }

static int user_max_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 773 of file app_meetme.c.

References ast_conf_user::user_no.

Referenced by admin_exec(), and conf_run().

00774 {
00775    struct ast_conf_user *user = obj;
00776    int *max_no = arg;
00777 
00778    if (user->user_no > *max_no) {
00779       *max_no = user->user_no;
00780    }
00781 
00782    return 0;
00783 }

static int user_no_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 761 of file app_meetme.c.

References ast_conf_user::user_no.

Referenced by build_conf().

00762 {
00763    struct ast_conf_user *user = obj;
00764    int *user_no = arg;
00765 
00766    if (user->user_no == *user_no) {
00767       return (CMP_MATCH | CMP_STOP);
00768    }
00769 
00770    return 0;
00771 }

static int user_reset_vol_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 3114 of file app_meetme.c.

References reset_volumes().

Referenced by admin_exec().

03115 {
03116    struct ast_conf_user *user = obj;
03117    reset_volumes(user);
03118    return 0;
03119 }

static int user_set_kickme_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 3063 of file app_meetme.c.

References ADMINFLAG_KICKME, and ast_conf_user::adminflags.

Referenced by admin_exec().

03064 {
03065    struct ast_conf_user *user = obj;
03066    user->adminflags |= ADMINFLAG_KICKME;
03067    return 0;
03068 }

static int user_set_muted_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 3070 of file app_meetme.c.

References ADMINFLAG_MUTED, ast_conf_user::adminflags, and ast_conf_user::userflags.

Referenced by admin_exec().

03071 {
03072    struct ast_conf_user *user = obj;
03073    if (!(user->userflags & CONFFLAG_ADMIN)) {
03074       user->adminflags |= ADMINFLAG_MUTED;
03075    }
03076    return 0;
03077 }

static int user_set_unmuted_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 3079 of file app_meetme.c.

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, and ast_conf_user::adminflags.

Referenced by admin_exec().

03080 {
03081    struct ast_conf_user *user = obj;
03082    user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
03083    return 0;
03084 }

static int user_talk_voldown_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 3107 of file app_meetme.c.

References tweak_talk_volume().

Referenced by admin_exec().

03108 {
03109    struct ast_conf_user *user = obj;
03110    tweak_talk_volume(user, VOL_DOWN);
03111    return 0;
03112 }

static int user_talk_volup_cb ( void *  obj,
void *  unused,
int  flags 
) [static]

Definition at line 3100 of file app_meetme.c.

References tweak_talk_volume(), and VOL_UP.

Referenced by admin_exec().

03101 {
03102    struct ast_conf_user *user = obj;
03103    tweak_talk_volume(user, VOL_UP);
03104    return 0;
03105 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 5204 of file app_meetme.c.

const char* app = "MeetMe" [static]

Definition at line 210 of file app_meetme.c.

const char* app2 = "MeetMeCount" [static]

Definition at line 211 of file app_meetme.c.

const char* app3 = "MeetMeAdmin" [static]

Definition at line 212 of file app_meetme.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 5204 of file app_meetme.c.

unsigned int attempt_callerid

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

Definition at line 566 of file app_meetme.c.

int audio_buffers [static]

The number of audio buffers to be allocated on pseudo channels when in a conference

Definition at line 573 of file app_meetme.c.

Referenced by conf_run(), and load_config_meetme().

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1266 of file app_meetme.c.

Referenced by load_module(), and unload_module().

ast_cond_t cond

Definition at line 557 of file app_meetme.c.

Referenced by _macro_exec(), sla_handle_dial_state_event(), sla_station_exec(), and smdi_message_wait().

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

Definition at line 384 of file app_meetme.c.

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

const char* descrip [static]

Definition at line 222 of file app_meetme.c.

const char* descrip2 [static]

Definition at line 272 of file app_meetme.c.

const char* descrip3 [static]

Definition at line 279 of file app_meetme.c.

struct { ... } event_q

struct { ... } failed_stations

struct sla_event* first

Definition at line 562 of file app_meetme.c.

struct sla_failed_station* first

Definition at line 561 of file app_meetme.c.

struct sla_ringing_station* first

Definition at line 560 of file app_meetme.c.

struct sla_ringing_trunk* first

Definition at line 559 of file app_meetme.c.

Referenced by ast_format_str_reduce(), ast_print_group(), ast_rtp_new_with_bindaddr(), check_goto(), get_goto_target(), and misdn_lib_init().

char const gain_map[] [static]

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

Definition at line 581 of file app_meetme.c.

struct sla_event* last

Definition at line 562 of file app_meetme.c.

struct sla_failed_station* last

Definition at line 561 of file app_meetme.c.

struct sla_ringing_station* last

Definition at line 560 of file app_meetme.c.

struct sla_ringing_trunk* last

Definition at line 559 of file app_meetme.c.

Referenced by add_extensions(), aji_handle_presence(), ao2_callback(), apply_outgoing(), ast_config_engine_deregister(), ast_db_freetree(), ast_db_gettree(), config_odbc(), config_pgsql(), crypto_load(), directory_exec(), do_monitor(), gtalk_free_candidates(), load_password(), next_channel(), node_lookup(), scan_thread(), and try_firmware().

ast_mutex_t lock

Definition at line 558 of file app_meetme.c.

struct ast_app_option meetme_opts[128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'G' ] = { .flag = CONFFLAG_INTROMSG , .arg_index = OPT_ARG_INTROMSG + 1 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'M' ] = { .flag = CONFFLAG_MOH }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_POUNDEXIT }, [ '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 }, } [static]

Definition at line 208 of file app_meetme.c.

Referenced by conf_exec().

char meetme_usage[] [static]

Initial value:

"Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
"       Executes a command for the conference or on a conferee\n"

Definition at line 1116 of file app_meetme.c.

struct { ... } ringing_stations

struct { ... } ringing_trunks

struct { ... } sla [static]

A structure for data used by the sla thread.

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

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

Definition at line 502 of file app_meetme.c.

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

const char sla_show_stations_usage[] [static]

Initial value:

"Usage: sla show stations\n"
"       This will list all stations defined in sla.conf\n"

Definition at line 1262 of file app_meetme.c.

const char sla_show_trunks_usage[] [static]

Initial value:

"Usage: sla show trunks\n"
"       This will list all trunks defined in sla.conf\n"

Definition at line 1193 of file app_meetme.c.

const char* slastation_app = "SLAStation" [static]

Definition at line 213 of file app_meetme.c.

const char* slastation_desc [static]

Definition at line 302 of file app_meetme.c.

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

Definition at line 219 of file app_meetme.c.

const char* slatrunk_app = "SLATrunk" [static]

Definition at line 214 of file app_meetme.c.

const char* slatrunk_desc [static]

Definition at line 315 of file app_meetme.c.

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

Definition at line 220 of file app_meetme.c.

unsigned int stop

Definition at line 563 of file app_meetme.c.

Referenced by handle_controlstreamfile(), and queue_exec().

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

Definition at line 216 of file app_meetme.c.

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

Definition at line 217 of file app_meetme.c.

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

Definition at line 218 of file app_meetme.c.

pthread_t thread

The SLA thread ID

Definition at line 556 of file app_meetme.c.

Referenced by __schedule_action(), __unload_module(), ast_bridge_call_thread_launch(), find_idle_thread(), handle_deferred_full_frames(), iax2_process_thread(), iax2_process_thread_cleanup(), iax2_show_threads(), insert_idle_thread(), launch_monitor_thread(), load_module(), socket_process(), socket_read(), and start_network_thread().


Generated on Sat Aug 6 00:39:35 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7