Thu Mar 25 12:09:41 2010

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)

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

static void __unreg_module ( void   )  [static]

Definition at line 5085 of file app_meetme.c.

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

Definition at line 3198 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03199 {
03200    return meetmemute(s, m, 1);
03201 }

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

Definition at line 3203 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03204 {
03205    return meetmemute(s, m, 0);
03206 }

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

The MeetMeadmin application.

Definition at line 2984 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, AST_APP_ARG, ast_atomic_fetchadd_int(), AST_DECLARE_APP_ARGS, AST_LIST_LAST, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_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(), ast_conf_user::userflags, ast_conference::userlist, and VOL_UP.

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

02984                                                             {
02985    char *params;
02986    struct ast_conference *cnf;
02987    struct ast_conf_user *user = NULL;
02988    struct ast_module_user *u;
02989    AST_DECLARE_APP_ARGS(args,
02990       AST_APP_ARG(confno);
02991       AST_APP_ARG(command);
02992       AST_APP_ARG(user);
02993    );
02994 
02995    if (ast_strlen_zero(data)) {
02996       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
02997       return -1;
02998    }
02999 
03000    u = ast_module_user_add(chan);
03001 
03002    AST_LIST_LOCK(&confs);
03003    
03004    params = ast_strdupa(data);
03005    AST_STANDARD_APP_ARGS(args, params);
03006 
03007    if (!args.command) {
03008       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
03009       AST_LIST_UNLOCK(&confs);
03010       ast_module_user_remove(u);
03011       return -1;
03012    }
03013    AST_LIST_TRAVERSE(&confs, cnf, list) {
03014       if (!strcmp(cnf->confno, args.confno))
03015          break;
03016    }
03017 
03018    if (!cnf) {
03019       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
03020       AST_LIST_UNLOCK(&confs);
03021       ast_module_user_remove(u);
03022       return 0;
03023    }
03024 
03025    ast_atomic_fetchadd_int(&cnf->refcount, 1);
03026 
03027    if (args.user)
03028       user = find_user(cnf, args.user);
03029 
03030    switch (*args.command) {
03031    case 76: /* L: Lock */ 
03032       cnf->locked = 1;
03033       break;
03034    case 108: /* l: Unlock */ 
03035       cnf->locked = 0;
03036       break;
03037    case 75: /* K: kick all users */
03038       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03039          user->adminflags |= ADMINFLAG_KICKME;
03040       break;
03041    case 101: /* e: Eject last user*/
03042       user = AST_LIST_LAST(&cnf->userlist);
03043       if (!(user->userflags & CONFFLAG_ADMIN))
03044          user->adminflags |= ADMINFLAG_KICKME;
03045       else
03046          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
03047       break;
03048    case 77: /* M: Mute */ 
03049       if (user) {
03050          user->adminflags |= ADMINFLAG_MUTED;
03051       } else
03052          ast_log(LOG_NOTICE, "Specified User not found!\n");
03053       break;
03054    case 78: /* N: Mute all (non-admin) users */
03055       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03056          if (!(user->userflags & CONFFLAG_ADMIN))
03057             user->adminflags |= ADMINFLAG_MUTED;
03058       }
03059       break;               
03060    case 109: /* m: Unmute */ 
03061       if (user) {
03062          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
03063       } else
03064          ast_log(LOG_NOTICE, "Specified User not found!\n");
03065       break;
03066    case 110: /* n: Unmute all users */
03067       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03068          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
03069       break;
03070    case 107: /* k: Kick user */ 
03071       if (user)
03072          user->adminflags |= ADMINFLAG_KICKME;
03073       else
03074          ast_log(LOG_NOTICE, "Specified User not found!\n");
03075       break;
03076    case 118: /* v: Lower all users listen volume */
03077       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03078          tweak_listen_volume(user, VOL_DOWN);
03079       break;
03080    case 86: /* V: Raise all users listen volume */
03081       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03082          tweak_listen_volume(user, VOL_UP);
03083       break;
03084    case 115: /* s: Lower all users speaking volume */
03085       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03086          tweak_talk_volume(user, VOL_DOWN);
03087       break;
03088    case 83: /* S: Raise all users speaking volume */
03089       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03090          tweak_talk_volume(user, VOL_UP);
03091       break;
03092    case 82: /* R: Reset all volume levels */
03093       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03094          reset_volumes(user);
03095       break;
03096    case 114: /* r: Reset user's volume level */
03097       if (user)
03098          reset_volumes(user);
03099       else
03100          ast_log(LOG_NOTICE, "Specified User not found!\n");
03101       break;
03102    case 85: /* U: Raise user's listen volume */
03103       if (user)
03104          tweak_listen_volume(user, VOL_UP);
03105       else
03106          ast_log(LOG_NOTICE, "Specified User not found!\n");
03107       break;
03108    case 117: /* u: Lower user's listen volume */
03109       if (user)
03110          tweak_listen_volume(user, VOL_DOWN);
03111       else
03112          ast_log(LOG_NOTICE, "Specified User not found!\n");
03113       break;
03114    case 84: /* T: Raise user's talk volume */
03115       if (user)
03116          tweak_talk_volume(user, VOL_UP);
03117       else
03118          ast_log(LOG_NOTICE, "Specified User not found!\n");
03119       break;
03120    case 116: /* t: Lower user's talk volume */
03121       if (user) 
03122          tweak_talk_volume(user, VOL_DOWN);
03123       else 
03124          ast_log(LOG_NOTICE, "Specified User not found!\n");
03125       break;
03126    }
03127 
03128    AST_LIST_UNLOCK(&confs);
03129 
03130    dispose_conf(cnf);
03131 
03132    ast_module_user_remove(u);
03133    
03134    return 0;
03135 }

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

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

01440 {
01441    struct announce_listitem *current;
01442    struct ast_conference *conf = data;
01443    int res;
01444    char filename[PATH_MAX] = "";
01445    AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
01446    AST_LIST_HEAD_INIT_NOLOCK(&local_list);
01447 
01448    while (!conf->announcethread_stop) {
01449       ast_mutex_lock(&conf->announcelistlock);
01450       if (conf->announcethread_stop) {
01451          ast_mutex_unlock(&conf->announcelistlock);
01452          break;
01453       }
01454       if (AST_LIST_EMPTY(&conf->announcelist))
01455          ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
01456 
01457       AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
01458       AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01459 
01460       ast_mutex_unlock(&conf->announcelistlock);
01461       if (conf->announcethread_stop) {
01462          break;
01463       }
01464 
01465       for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
01466          ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
01467          if (!ast_fileexists(current->namerecloc, NULL, NULL))
01468             continue;
01469          if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
01470             if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
01471                res = ast_waitstream(current->confchan, "");
01472             if (!res) {
01473                ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
01474                if (!ast_streamfile(current->confchan, filename, current->language))
01475                   ast_waitstream(current->confchan, "");
01476             }
01477          }
01478          if (current->announcetype == CONF_HASLEFT) {
01479             ast_filedelete(current->namerecloc, NULL);
01480          }
01481       }
01482    }
01483 
01484    /* thread marked to stop, clean up */
01485    while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
01486       ast_filedelete(current->namerecloc, NULL);
01487       ao2_ref(current, -1);
01488    }
01489    return NULL;
01490 }

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

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

03455 {
03456    ast_answer(chan);
03457    ast_indicate(chan, -1);
03458 }

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

References 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_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, and VERBOSE_PREFIX_3.

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

00775 {
00776    struct ast_conference *cnf;
00777    struct dahdi_confinfo ztc = { 0, };
00778    int confno_int = 0;
00779 
00780    AST_LIST_LOCK(&confs);
00781 
00782    AST_LIST_TRAVERSE(&confs, cnf, list) {
00783       if (!strcmp(confno, cnf->confno)) 
00784          break;
00785    }
00786 
00787    if (cnf || (!make && !dynamic))
00788       goto cnfout;
00789 
00790    /* Make a new one */
00791    if (!(cnf = ast_calloc(1, sizeof(*cnf))))
00792       goto cnfout;
00793 
00794    ast_mutex_init(&cnf->playlock);
00795    ast_mutex_init(&cnf->listenlock);
00796    cnf->recordthread = AST_PTHREADT_NULL;
00797    ast_mutex_init(&cnf->recordthreadlock);
00798    cnf->announcethread = AST_PTHREADT_NULL;
00799    ast_mutex_init(&cnf->announcethreadlock);
00800    ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00801    ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00802    ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00803 
00804    /* Setup a new zap conference */
00805    ztc.confno = -1;
00806    ztc.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00807    cnf->fd = open(DAHDI_FILE_PSEUDO, O_RDWR);
00808    if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &ztc)) {
00809       ast_log(LOG_WARNING, "Unable to open pseudo device\n");
00810       if (cnf->fd >= 0)
00811          close(cnf->fd);
00812       free(cnf);
00813       cnf = NULL;
00814       goto cnfout;
00815    }
00816 
00817    cnf->zapconf = ztc.confno;
00818 
00819    /* Setup a new channel for playback of audio files */
00820    cnf->chan = ast_request(dahdi_chan_name, AST_FORMAT_SLINEAR, "pseudo", NULL);
00821    if (cnf->chan) {
00822       ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
00823       ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
00824       ztc.chan = 0;
00825       ztc.confno = cnf->zapconf;
00826       ztc.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00827       if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &ztc)) {
00828          ast_log(LOG_WARNING, "Error setting conference\n");
00829          if (cnf->chan)
00830             ast_hangup(cnf->chan);
00831          else
00832             close(cnf->fd);
00833          free(cnf);
00834          cnf = NULL;
00835          goto cnfout;
00836       }
00837    }
00838 
00839    /* Fill the conference struct */
00840    cnf->start = time(NULL);
00841    cnf->isdynamic = dynamic ? 1 : 0;
00842    if (option_verbose > 2)
00843       ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
00844    AST_LIST_INSERT_HEAD(&confs, cnf, list);
00845 
00846    /* Reserve conference number in map */
00847    if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
00848       conf_map[confno_int] = 1;
00849    
00850 cnfout:
00851    if (cnf)
00852       ast_atomic_fetchadd_int(&cnf->refcount, refcount);
00853 
00854    AST_LIST_UNLOCK(&confs);
00855 
00856    return cnf;
00857 }

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

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

01493 {
01494    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01495       return 1;
01496    }
01497 
01498    return (chan->_state == AST_STATE_UP);
01499 }

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

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

01008 {
01009    static char *cmds[] = {"lock", "unlock", "mute", "unmute", "kick", "list", NULL};
01010 
01011    int len = strlen(word);
01012    int which = 0;
01013    struct ast_conference *cnf = NULL;
01014    struct ast_conf_user *usr = NULL;
01015    char *confno = NULL;
01016    char usrno[50] = "";
01017    char *myline, *ret = NULL;
01018    
01019    if (pos == 1) {      /* Command */
01020       return ast_cli_complete(word, cmds, state);
01021    } else if (pos == 2) {  /* Conference Number */
01022       AST_LIST_LOCK(&confs);
01023       AST_LIST_TRAVERSE(&confs, cnf, list) {
01024          if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
01025             ret = cnf->confno;
01026             break;
01027          }
01028       }
01029       ret = ast_strdup(ret); /* dup before releasing the lock */
01030       AST_LIST_UNLOCK(&confs);
01031       return ret;
01032    } else if (pos == 3) {
01033       /* User Number || Conf Command option*/
01034       if (strstr(line, "mute") || strstr(line, "kick")) {
01035          if (state == 0 && (strstr(line, "kick") || strstr(line,"mute")) && !strncasecmp(word, "all", len))
01036             return strdup("all");
01037          which++;
01038          AST_LIST_LOCK(&confs);
01039 
01040          /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
01041          myline = ast_strdupa(line);
01042          if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
01043             while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
01044                ;
01045          }
01046          
01047          AST_LIST_TRAVERSE(&confs, cnf, list) {
01048             if (!strcmp(confno, cnf->confno))
01049                 break;
01050          }
01051 
01052          if (cnf) {
01053             /* Search for the user */
01054             AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
01055                snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
01056                if (!strncasecmp(word, usrno, len) && ++which > state)
01057                   break;
01058             }
01059          }
01060          AST_LIST_UNLOCK(&confs);
01061          return usr ? strdup(usrno) : NULL;
01062       } else if ( strstr(line, "list") && ( 0 == state ) )
01063          return strdup("concise");
01064    }
01065 
01066    return NULL;
01067 }

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

The meetme() application.

Definition at line 2722 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, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, MAX_SETTINGS, meetme_opts, OPT_ARG_ARRAY_SIZE, parse(), ast_conference::pin, ast_conference::pinadmin, and var.

02723 {
02724    int res=-1;
02725    struct ast_module_user *u;
02726    char confno[MAX_CONFNUM] = "";
02727    int allowretry = 0;
02728    int retrycnt = 0;
02729    struct ast_conference *cnf = NULL;
02730    struct ast_flags confflags = {0};
02731    int dynamic = 0;
02732    int empty = 0, empty_no_pin = 0;
02733    int always_prompt = 0;
02734    char *notdata, *info, the_pin[MAX_PIN] = "";
02735    AST_DECLARE_APP_ARGS(args,
02736       AST_APP_ARG(confno);
02737       AST_APP_ARG(options);
02738       AST_APP_ARG(pin);
02739    );
02740    char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
02741 
02742    u = ast_module_user_add(chan);
02743 
02744    if (ast_strlen_zero(data)) {
02745       allowretry = 1;
02746       notdata = "";
02747    } else {
02748       notdata = data;
02749    }
02750    
02751    if (chan->_state != AST_STATE_UP)
02752       ast_answer(chan);
02753 
02754    info = ast_strdupa(notdata);
02755 
02756    AST_STANDARD_APP_ARGS(args, info);  
02757 
02758    if (args.confno) {
02759       ast_copy_string(confno, args.confno, sizeof(confno));
02760       if (ast_strlen_zero(confno)) {
02761          allowretry = 1;
02762       }
02763    }
02764    
02765    if (args.pin)
02766       ast_copy_string(the_pin, args.pin, sizeof(the_pin));
02767 
02768    if (args.options) {
02769       ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
02770       dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
02771       if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
02772          strcpy(the_pin, "q");
02773 
02774       empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
02775       empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
02776       always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
02777    }
02778 
02779    do {
02780       if (retrycnt > 3)
02781          allowretry = 0;
02782       if (empty) {
02783          int i;
02784          struct ast_config *cfg;
02785          struct ast_variable *var;
02786          int confno_int;
02787 
02788          /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
02789          if ((empty_no_pin) || (!dynamic)) {
02790             cfg = ast_config_load(CONFIG_FILE_NAME);
02791             if (cfg) {
02792                var = ast_variable_browse(cfg, "rooms");
02793                while (var) {
02794                   char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
02795                   if (!strcasecmp(var->name, "conf")) {
02796                      int found = 0;
02797                      ast_copy_string(parse, var->value, sizeof(parse));
02798                      confno_tmp = strsep(&stringp, "|,");
02799                      if (!dynamic) {
02800                         /* For static:  run through the list and see if this conference is empty */
02801                         AST_LIST_LOCK(&confs);
02802                         AST_LIST_TRAVERSE(&confs, cnf, list) {
02803                            if (!strcmp(confno_tmp, cnf->confno)) {
02804                               /* The conference exists, therefore it's not empty */
02805                               found = 1;
02806                               break;
02807                            }
02808                         }
02809                         AST_LIST_UNLOCK(&confs);
02810                         if (!found) {
02811                            /* At this point, we have a confno_tmp (static conference) that is empty */
02812                            if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
02813                               /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
02814                                * Case 2:  empty_no_pin and pin is blank (but not NULL)
02815                                * Case 3:  not empty_no_pin
02816                                */
02817                               ast_copy_string(confno, confno_tmp, sizeof(confno));
02818                               break;
02819                               /* XXX the map is not complete (but we do have a confno) */
02820                            }
02821                         }
02822                      }
02823                   }
02824                   var = var->next;
02825                }
02826                ast_config_destroy(cfg);
02827             }
02828          }
02829 
02830          /* Select first conference number not in use */
02831          if (ast_strlen_zero(confno) && dynamic) {
02832             AST_LIST_LOCK(&confs);
02833             for (i = 0; i < sizeof(conf_map) / sizeof(conf_map[0]); i++) {
02834                if (!conf_map[i]) {
02835                   snprintf(confno, sizeof(confno), "%d", i);
02836                   conf_map[i] = 1;
02837                   break;
02838                }
02839             }
02840             AST_LIST_UNLOCK(&confs);
02841          }
02842 
02843          /* Not found? */
02844          if (ast_strlen_zero(confno)) {
02845             res = ast_streamfile(chan, "conf-noempty", chan->language);
02846             if (!res)
02847                ast_waitstream(chan, "");
02848          } else {
02849             if (sscanf(confno, "%30d", &confno_int) == 1) {
02850                res = ast_streamfile(chan, "conf-enteringno", chan->language);
02851                if (!res) {
02852                   ast_waitstream(chan, "");
02853                   res = ast_say_digits(chan, confno_int, "", chan->language);
02854                }
02855             } else {
02856                ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
02857             }
02858          }
02859       }
02860 
02861       while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
02862          /* Prompt user for conference number */
02863          res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
02864          if (res < 0) {
02865             /* Don't try to validate when we catch an error */
02866             confno[0] = '\0';
02867             allowretry = 0;
02868             break;
02869          }
02870       }
02871       if (!ast_strlen_zero(confno)) {
02872          /* Check the validity of the conference */
02873          cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
02874             sizeof(the_pin), 1, &confflags);
02875          if (!cnf) {
02876             cnf = find_conf_realtime(chan, confno, 1, dynamic, 
02877                the_pin, sizeof(the_pin), 1, &confflags);
02878          }
02879 
02880          if (!cnf) {
02881             res = ast_streamfile(chan, "conf-invalid", chan->language);
02882             if (!res)
02883                ast_waitstream(chan, "");
02884             res = -1;
02885             if (allowretry)
02886                confno[0] = '\0';
02887          } else {
02888             if ((!ast_strlen_zero(cnf->pin) &&
02889                  !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
02890                 (!ast_strlen_zero(cnf->pinadmin) &&
02891                  ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
02892                char pin[MAX_PIN] = "";
02893                int j;
02894 
02895                /* Allow the pin to be retried up to 3 times */
02896                for (j = 0; j < 3; j++) {
02897                   if (*the_pin && (always_prompt == 0)) {
02898                      ast_copy_string(pin, the_pin, sizeof(pin));
02899                      res = 0;
02900                   } else {
02901                      /* Prompt user for pin if pin is required */
02902                      res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
02903                   }
02904                   if (res >= 0) {
02905                      if (!strcasecmp(pin, cnf->pin) ||
02906                          (!ast_strlen_zero(cnf->pinadmin) &&
02907                           !strcasecmp(pin, cnf->pinadmin))) {
02908                         /* Pin correct */
02909                         allowretry = 0;
02910                         if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
02911                            ast_set_flag(&confflags, CONFFLAG_ADMIN);
02912                         /* Run the conference */
02913                         res = conf_run(chan, cnf, confflags.flags, optargs);
02914                         break;
02915                      } else {
02916                         /* Pin invalid */
02917                         if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
02918                            res = ast_waitstream(chan, AST_DIGIT_ANY);
02919                            ast_stopstream(chan);
02920                         }
02921                         else {
02922                            ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
02923                            break;
02924                         }
02925                         if (res < 0)
02926                            break;
02927                         pin[0] = res;
02928                         pin[1] = '\0';
02929                         res = -1;
02930                         if (allowretry)
02931                            confno[0] = '\0';
02932                      }
02933                   } else {
02934                      /* failed when getting the pin */
02935                      res = -1;
02936                      allowretry = 0;
02937                      /* see if we need to get rid of the conference */
02938                      break;
02939                   }
02940 
02941                   /* Don't retry pin with a static pin */
02942                   if (*the_pin && (always_prompt==0)) {
02943                      break;
02944                   }
02945                }
02946             } else {
02947                /* No pin required */
02948                allowretry = 0;
02949 
02950                /* Run the conference */
02951                res = conf_run(chan, cnf, confflags.flags, optargs);
02952             }
02953             dispose_conf(cnf);
02954             cnf = NULL;
02955          }
02956       }
02957    } while (allowretry);
02958 
02959    if (cnf)
02960       dispose_conf(cnf);
02961 
02962    ast_module_user_remove(u);
02963    
02964    return res;
02965 }

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

Definition at line 1233 of file app_meetme.c.

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

Referenced by conf_run().

01234 {
01235    int x;
01236 
01237    /* read any frames that may be waiting on the channel
01238       and throw them away
01239    */
01240    if (chan) {
01241       struct ast_frame *f;
01242 
01243       /* when no frames are available, this will wait
01244          for 1 millisecond maximum
01245       */
01246       while (ast_waitfor(chan, 1)) {
01247          f = ast_read(chan);
01248          if (f)
01249             ast_frfree(f);
01250          else /* channel was hung up or something else happened */
01251             break;
01252       }
01253    }
01254 
01255    /* flush any data sitting in the pseudo channel */
01256    x = DAHDI_FLUSH_ALL;
01257    if (ioctl(fd, DAHDI_FLUSH, &x))
01258       ast_log(LOG_WARNING, "Error flushing channel\n");
01259 
01260 }

static int conf_free ( struct ast_conference conf  )  [static]

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

01265 {
01266    int x;
01267    struct announce_listitem *item;
01268    
01269    AST_LIST_REMOVE(&confs, conf, list);
01270 
01271    if (conf->recording == MEETME_RECORD_ACTIVE) {
01272       conf->recording = MEETME_RECORD_TERMINATE;
01273       AST_LIST_UNLOCK(&confs);
01274       while (1) {
01275          usleep(1);
01276          AST_LIST_LOCK(&confs);
01277          if (conf->recording == MEETME_RECORD_OFF)
01278             break;
01279          AST_LIST_UNLOCK(&confs);
01280       }
01281    }
01282 
01283    for (x=0;x<AST_FRAME_BITS;x++) {
01284       if (conf->transframe[x])
01285          ast_frfree(conf->transframe[x]);
01286       if (conf->transpath[x])
01287          ast_translator_free_path(conf->transpath[x]);
01288    }
01289    if (conf->announcethread != AST_PTHREADT_NULL) {
01290       ast_mutex_lock(&conf->announcelistlock);
01291       conf->announcethread_stop = 1;
01292       ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01293       ast_cond_signal(&conf->announcelist_addition);
01294       ast_mutex_unlock(&conf->announcelistlock);
01295       pthread_join(conf->announcethread, NULL);
01296    
01297       while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01298          ast_filedelete(item->namerecloc, NULL);
01299          ao2_ref(item, -1);
01300       }
01301       ast_mutex_destroy(&conf->announcelistlock);
01302    }
01303    if (conf->origframe)
01304       ast_frfree(conf->origframe);
01305    if (conf->lchan)
01306       ast_hangup(conf->lchan);
01307    if (conf->chan)
01308       ast_hangup(conf->chan);
01309    if (conf->fd >= 0)
01310       close(conf->fd);
01311 
01312    ast_mutex_destroy(&conf->playlock);
01313    ast_mutex_destroy(&conf->listenlock);
01314    ast_mutex_destroy(&conf->recordthreadlock);
01315    ast_mutex_destroy(&conf->announcethreadlock);
01316 
01317    free(conf);
01318 
01319    return 0;
01320 }

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

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

Referenced by conf_run().

01324 {
01325    struct ast_conf_user *user;
01326 
01327    AST_LIST_TRAVERSE(&conf->userlist, user, list) {
01328       if (user == sender)
01329          continue;
01330       if (ast_write(user->chan, f) < 0)
01331          ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01332    }
01333 }

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

Definition at line 1530 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_ref(), app, ast_calloc, ast_channel_setoption(), ast_check_hangup(), ast_cond_signal(), ast_config_AST_SPOOL_DIR, AST_CONTROL_HOLD, ast_copy_string(), ast_device_state_changed(), AST_DIGIT_ANY, 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_EMPTY, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LAST, 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::frame_list, 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, ast_conf_user::userflags, ast_conference::userlist, ast_conference::users, VERBOSE_PREFIX_4, VOL_UP, and ast_conference::zapconf.

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

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

The MeetmeCount application.

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

02672 {
02673    struct ast_module_user *u;
02674    int res = 0;
02675    struct ast_conference *conf;
02676    int count;
02677    char *localdata;
02678    char val[80] = "0"; 
02679    AST_DECLARE_APP_ARGS(args,
02680       AST_APP_ARG(confno);
02681       AST_APP_ARG(varname);
02682    );
02683 
02684    if (ast_strlen_zero(data)) {
02685       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
02686       return -1;
02687    }
02688 
02689    u = ast_module_user_add(chan);
02690    
02691    if (!(localdata = ast_strdupa(data))) {
02692       ast_module_user_remove(u);
02693       return -1;
02694    }
02695 
02696    AST_STANDARD_APP_ARGS(args, localdata);
02697    
02698    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
02699 
02700    if (conf) {
02701       count = conf->users;
02702       dispose_conf(conf);
02703       conf = NULL;
02704    } else
02705       count = 0;
02706 
02707    if (!ast_strlen_zero(args.varname)){
02708       /* have var so load it and exit */
02709       snprintf(val, sizeof(val), "%d",count);
02710       pbx_builtin_setvar_helper(chan, args.varname, val);
02711    } else {
02712       if (chan->_state != AST_STATE_UP)
02713          ast_answer(chan);
02714       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
02715    }
02716    ast_module_user_remove(u);
02717 
02718    return res;
02719 }

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

Definition at line 4494 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

04495 {
04496    struct sla_trunk_ref *trunk_ref;
04497 
04498    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
04499       return NULL;
04500 
04501    trunk_ref->trunk = trunk;
04502 
04503    return trunk_ref;
04504 }

static void destroy_station ( struct sla_station station  )  [static]

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

04663 {
04664    struct sla_trunk_ref *trunk_ref;
04665 
04666    if (!ast_strlen_zero(station->autocontext)) {
04667       AST_RWLIST_RDLOCK(&sla_trunks);
04668       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04669          char exten[AST_MAX_EXTENSION];
04670          char hint[AST_MAX_APP];
04671          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04672          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04673          ast_context_remove_extension(station->autocontext, exten, 
04674             1, sla_registrar);
04675          ast_context_remove_extension(station->autocontext, hint, 
04676             PRIORITY_HINT, sla_registrar);
04677       }
04678       AST_RWLIST_UNLOCK(&sla_trunks);
04679    }
04680 
04681    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
04682       free(trunk_ref);
04683 
04684    ast_string_field_free_memory(station);
04685    free(station);
04686 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

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

04649 {
04650    struct sla_station_ref *station_ref;
04651 
04652    if (!ast_strlen_zero(trunk->autocontext))
04653       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
04654 
04655    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
04656       free(station_ref);
04657 
04658    ast_string_field_free_memory(trunk);
04659    free(trunk);
04660 }

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

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

04214 {
04215    struct dial_trunk_args *args = data;
04216    struct ast_dial *dial;
04217    char *tech, *tech_data;
04218    enum ast_dial_result dial_res;
04219    char conf_name[MAX_CONFNUM];
04220    struct ast_conference *conf;
04221    struct ast_flags conf_flags = { 0 };
04222    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
04223    const char *cid_name = NULL, *cid_num = NULL;
04224 
04225    if (!(dial = ast_dial_create())) {
04226       ast_mutex_lock(args->cond_lock);
04227       ast_cond_signal(args->cond);
04228       ast_mutex_unlock(args->cond_lock);
04229       return NULL;
04230    }
04231 
04232    tech_data = ast_strdupa(trunk_ref->trunk->device);
04233    tech = strsep(&tech_data, "/");
04234    if (ast_dial_append(dial, tech, tech_data) == -1) {
04235       ast_mutex_lock(args->cond_lock);
04236       ast_cond_signal(args->cond);
04237       ast_mutex_unlock(args->cond_lock);
04238       ast_dial_destroy(dial);
04239       return NULL;
04240    }
04241 
04242    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
04243       cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
04244       free(trunk_ref->chan->cid.cid_name);
04245       trunk_ref->chan->cid.cid_name = NULL;
04246    }
04247    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
04248       cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
04249       free(trunk_ref->chan->cid.cid_num);
04250       trunk_ref->chan->cid.cid_num = NULL;
04251    }
04252 
04253    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
04254 
04255    if (cid_name)
04256       trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
04257    if (cid_num)
04258       trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
04259 
04260    if (dial_res != AST_DIAL_RESULT_TRYING) {
04261       ast_mutex_lock(args->cond_lock);
04262       ast_cond_signal(args->cond);
04263       ast_mutex_unlock(args->cond_lock);
04264       ast_dial_destroy(dial);
04265       return NULL;
04266    }
04267 
04268    for (;;) {
04269       unsigned int done = 0;
04270       switch ((dial_res = ast_dial_state(dial))) {
04271       case AST_DIAL_RESULT_ANSWERED:
04272          trunk_ref->trunk->chan = ast_dial_answered(dial);
04273       case AST_DIAL_RESULT_HANGUP:
04274       case AST_DIAL_RESULT_INVALID:
04275       case AST_DIAL_RESULT_FAILED:
04276       case AST_DIAL_RESULT_TIMEOUT:
04277       case AST_DIAL_RESULT_UNANSWERED:
04278          done = 1;
04279       case AST_DIAL_RESULT_TRYING:
04280       case AST_DIAL_RESULT_RINGING:
04281       case AST_DIAL_RESULT_PROGRESS:
04282       case AST_DIAL_RESULT_PROCEEDING:
04283          break;
04284       }
04285       if (done)
04286          break;
04287    }
04288 
04289    if (!trunk_ref->trunk->chan) {
04290       ast_mutex_lock(args->cond_lock);
04291       ast_cond_signal(args->cond);
04292       ast_mutex_unlock(args->cond_lock);
04293       ast_dial_join(dial);
04294       ast_dial_destroy(dial);
04295       return NULL;
04296    }
04297 
04298    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04299    ast_set_flag(&conf_flags, 
04300       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
04301       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
04302    conf = build_conf(conf_name, "", "", 1, 1, 1);
04303 
04304    ast_mutex_lock(args->cond_lock);
04305    ast_cond_signal(args->cond);
04306    ast_mutex_unlock(args->cond_lock);
04307 
04308    if (conf) {
04309       conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
04310       dispose_conf(conf);
04311       conf = NULL;
04312    }
04313 
04314    /* If the trunk is going away, it is definitely now IDLE. */
04315    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04316 
04317    trunk_ref->trunk->chan = NULL;
04318    trunk_ref->trunk->on_hold = 0;
04319 
04320    ast_dial_join(dial);
04321    ast_dial_destroy(dial);
04322 
04323    return NULL;
04324 }

static int dispose_conf ( struct ast_conference conf  )  [static]

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

01408 {
01409    int res = 0;
01410    int confno_int = 0;
01411 
01412    AST_LIST_LOCK(&confs);
01413    if (ast_atomic_dec_and_test(&conf->refcount)) {
01414       /* Take the conference room number out of an inuse state */
01415       if ((sscanf(conf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01416          conf_map[confno_int] = 0;
01417       conf_free(conf);
01418       res = 1;
01419    }
01420    AST_LIST_UNLOCK(&confs);
01421 
01422    return res;
01423 }

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

02578 {
02579    struct ast_config *cfg;
02580    struct ast_variable *var;
02581    struct ast_conference *cnf;
02582    AST_DECLARE_APP_ARGS(args,
02583       AST_APP_ARG(confno);
02584       AST_APP_ARG(pin);
02585       AST_APP_ARG(pinadmin);
02586    );
02587 
02588    /* Check first in the conference list */
02589    AST_LIST_LOCK(&confs);
02590    AST_LIST_TRAVERSE(&confs, cnf, list) {
02591       if (!strcmp(confno, cnf->confno)) 
02592          break;
02593    }
02594    if (cnf){
02595       cnf->refcount += refcount;
02596    }
02597    AST_LIST_UNLOCK(&confs);
02598 
02599    if (!cnf) {
02600       if (dynamic) {
02601          /* No need to parse meetme.conf */
02602          ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
02603          if (dynamic_pin) {
02604             if (dynamic_pin[0] == 'q') {
02605                /* Query the user to enter a PIN */
02606                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
02607                   return NULL;
02608             }
02609             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount);
02610          } else {
02611             cnf = build_conf(confno, "", "", make, dynamic, refcount);
02612          }
02613       } else {
02614          /* Check the config */
02615          cfg = ast_config_load(CONFIG_FILE_NAME);
02616          if (!cfg) {
02617             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
02618             return NULL;
02619          }
02620 
02621          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
02622             char parse[MAX_SETTINGS];
02623 
02624             if (strcasecmp(var->name, "conf"))
02625                continue;
02626 
02627             ast_copy_string(parse, var->value, sizeof(parse));
02628 
02629             AST_NONSTANDARD_APP_ARGS(args, parse, ',');
02630             if (!strcasecmp(args.confno, confno)) {
02631                /* Bingo it's a valid conference */
02632                cnf = build_conf(args.confno,
02633                      S_OR(args.pin, ""),
02634                      S_OR(args.pinadmin, ""),
02635                      make, dynamic, refcount);
02636                break;
02637             }
02638          }
02639          if (!var) {
02640             ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
02641          }
02642          ast_config_destroy(cfg);
02643       }
02644    } else if (dynamic_pin) {
02645       /* Correct for the user selecting 'D' instead of 'd' to have
02646          someone join into a conference that has already been created
02647          with a pin. */
02648       if (dynamic_pin[0] == 'q')
02649          dynamic_pin[0] = '\0';
02650    }
02651 
02652    if (cnf) {
02653       if (confflags && !cnf->chan &&
02654           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
02655           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
02656          ast_log(LOG_WARNING, "No %s channel available for conference, user introduction disabled\n", dahdi_chan_name);
02657          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
02658       }
02659       
02660       if (confflags && !cnf->chan &&
02661           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
02662          ast_log(LOG_WARNING, "No %s channel available for conference, conference recording disabled\n", dahdi_chan_name);
02663          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
02664       }
02665    }
02666 
02667    return cnf;
02668 }

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

02520 {
02521    struct ast_variable *var, *save;
02522    struct ast_conference *cnf;
02523 
02524    /* Check first in the conference list */
02525    AST_LIST_LOCK(&confs);
02526    AST_LIST_TRAVERSE(&confs, cnf, list) {
02527       if (!strcmp(confno, cnf->confno)) 
02528          break;
02529    }
02530    if (cnf) {
02531       cnf->refcount += refcount;
02532    }
02533    AST_LIST_UNLOCK(&confs);
02534 
02535    if (!cnf) {
02536       char *pin = NULL, *pinadmin = NULL; /* For temp use */
02537       
02538       var = ast_load_realtime("meetme", "confno", confno, NULL);
02539 
02540       if (!var)
02541          return NULL;
02542 
02543       save = var;
02544       while (var) {
02545          if (!strcasecmp(var->name, "pin")) {
02546             pin = ast_strdupa(var->value);
02547          } else if (!strcasecmp(var->name, "adminpin")) {
02548             pinadmin = ast_strdupa(var->value);
02549          }
02550          var = var->next;
02551       }
02552       ast_variables_destroy(save);
02553       
02554       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount);
02555    }
02556 
02557    if (cnf) {
02558       if (confflags && !cnf->chan &&
02559           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
02560           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
02561          ast_log(LOG_WARNING, "No %s channel available for conference, user introduction disabled\n", dahdi_chan_name);
02562          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
02563       }
02564       
02565       if (confflags && !cnf->chan &&
02566           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
02567          ast_log(LOG_WARNING, "No %s channel available for conference, conference recording disabled\n", dahdi_chan_name);
02568          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
02569       }
02570    }
02571 
02572    return cnf;
02573 }

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

Definition at line 2967 of file app_meetme.c.

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

02968 {
02969    struct ast_conf_user *user = NULL;
02970    int cid;
02971    
02972    sscanf(callerident, "%30i", &cid);
02973    if (conf && callerident) {
02974       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
02975          if (cid == user->user_no)
02976             return user;
02977       }
02978    }
02979    return NULL;
02980 }

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

Definition at line 1425 of file app_meetme.c.

References CONF_HASJOIN.

Referenced by announce_thread().

01426 {
01427    switch (type) {
01428    case CONF_HASLEFT:
01429       return "conf-hasleft";
01430       break;
01431    case CONF_HASJOIN:
01432       return "conf-hasjoin";
01433       break;
01434    default:
01435       return "";
01436    }
01437 }

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

References load_config_meetme(), and sla_load_config().

05018 {
05019    int res = 0;
05020 
05021    load_config_meetme();
05022    if (!reload)
05023       res = sla_load_config();
05024 
05025    return res;
05026 }

static void load_config_meetme ( void   )  [static]

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

03296 {
03297    struct ast_config *cfg;
03298    const char *val;
03299 
03300    audio_buffers = DEFAULT_AUDIO_BUFFERS;
03301 
03302    if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
03303       return;
03304 
03305    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03306       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
03307          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03308          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03309       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
03310          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03311             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
03312          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03313       }
03314       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03315          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03316    }
03317 
03318    ast_config_destroy(cfg);
03319 }

static int load_module ( void   )  [static]

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

05052 {
05053    int res = 0;
05054 
05055    res |= load_config(0);
05056 
05057    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05058    res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 
05059                 action_meetmemute, "Mute a Meetme user");
05060    res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 
05061                 action_meetmeunmute, "Unmute a Meetme user");
05062    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
05063    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
05064    res |= ast_register_application(app, conf_exec, synopsis, descrip);
05065    res |= ast_register_application(slastation_app, sla_station_exec,
05066                slastation_synopsis, slastation_desc);
05067    res |= ast_register_application(slatrunk_app, sla_trunk_exec,
05068                slatrunk_synopsis, slatrunk_desc);
05069 
05070    res |= ast_devstate_prov_add("Meetme", meetmestate);
05071    res |= ast_devstate_prov_add("SLA", sla_state);
05072 
05073    return res;
05074 }

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

Definition at line 859 of file app_meetme.c.

References admin_exec(), ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, 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_conf_user::userflags, ast_conference::userlist, and ast_conference::users.

00860 {
00861    /* Process the command */
00862    struct ast_conference *cnf;
00863    struct ast_conf_user *user;
00864    int hr, min, sec;
00865    int i = 0, total = 0;
00866    time_t now;
00867    char *header_format = "%-14s %-14s %-10s %-8s  %-8s\n";
00868    char *data_format = "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s\n";
00869    char cmdline[1024] = "";
00870 
00871    if (argc > 8)
00872       ast_cli(fd, "Invalid Arguments.\n");
00873    /* Check for length so no buffer will overflow... */
00874    for (i = 0; i < argc; i++) {
00875       if (strlen(argv[i]) > 100)
00876          ast_cli(fd, "Invalid Arguments.\n");
00877    }
00878    if (argc == 1) {
00879       /* 'MeetMe': List all the conferences */  
00880       now = time(NULL);
00881       AST_LIST_LOCK(&confs);
00882       if (AST_LIST_EMPTY(&confs)) {
00883          ast_cli(fd, "No active MeetMe conferences.\n");
00884          AST_LIST_UNLOCK(&confs);
00885          return RESULT_SUCCESS;
00886       }
00887       ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
00888       AST_LIST_TRAVERSE(&confs, cnf, list) {
00889          if (cnf->markedusers == 0)
00890             strcpy(cmdline, "N/A ");
00891          else 
00892             snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers);
00893          hr = (now - cnf->start) / 3600;
00894          min = ((now - cnf->start) % 3600) / 60;
00895          sec = (now - cnf->start) % 60;
00896 
00897          ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static");
00898 
00899          total += cnf->users;    
00900       }
00901       AST_LIST_UNLOCK(&confs);
00902       ast_cli(fd, "* Total number of MeetMe users: %d\n", total);
00903       return RESULT_SUCCESS;
00904    }
00905    if (argc < 3)
00906       return RESULT_SHOWUSAGE;
00907    ast_copy_string(cmdline, argv[2], sizeof(cmdline));   /* Argv 2: conference number */
00908    if (strstr(argv[1], "lock")) {   
00909       if (strcmp(argv[1], "lock") == 0) {
00910          /* Lock */
00911          strncat(cmdline, "|L", sizeof(cmdline) - strlen(cmdline) - 1);
00912       } else {
00913          /* Unlock */
00914          strncat(cmdline, "|l", sizeof(cmdline) - strlen(cmdline) - 1);
00915       }
00916    } else if (strstr(argv[1], "mute")) { 
00917       if (argc < 4)
00918          return RESULT_SHOWUSAGE;
00919       if (strcmp(argv[1], "mute") == 0) {
00920          /* Mute */
00921          if (strcmp(argv[3], "all") == 0) {
00922             strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1);
00923          } else {
00924             strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1);   
00925             strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00926          }
00927       } else {
00928          /* Unmute */
00929          if (strcmp(argv[3], "all") == 0) {
00930             strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1);
00931          } else {
00932             strncat(cmdline, "|m|", sizeof(cmdline) - strlen(cmdline) - 1);
00933             strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00934          }
00935       }
00936    } else if (strcmp(argv[1], "kick") == 0) {
00937       if (argc < 4)
00938          return RESULT_SHOWUSAGE;
00939       if (strcmp(argv[3], "all") == 0) {
00940          /* Kick all */
00941          strncat(cmdline, "|K", sizeof(cmdline) - strlen(cmdline) - 1);
00942       } else {
00943          /* Kick a single user */
00944          strncat(cmdline, "|k|", sizeof(cmdline) - strlen(cmdline) - 1);
00945          strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00946       }  
00947    } else if(strcmp(argv[1], "list") == 0) {
00948       int concise = ( 4 == argc && ( !strcasecmp(argv[3], "concise") ) );
00949       /* List all the users in a conference */
00950       if (AST_LIST_EMPTY(&confs)) {
00951          if ( !concise )
00952             ast_cli(fd, "No active conferences.\n");
00953          return RESULT_SUCCESS;  
00954       }
00955       /* Find the right conference */
00956       AST_LIST_LOCK(&confs);
00957       AST_LIST_TRAVERSE(&confs, cnf, list) {
00958          if (strcmp(cnf->confno, argv[2]) == 0)
00959             break;
00960       }
00961       if (!cnf) {
00962          if ( !concise )
00963             ast_cli(fd, "No such conference: %s.\n",argv[2]);
00964          AST_LIST_UNLOCK(&confs);
00965          return RESULT_SUCCESS;
00966       }
00967       /* Show all the users */
00968       time(&now);
00969       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
00970          hr = (now - user->jointime) / 3600;
00971          min = ((now - user->jointime) % 3600) / 60;
00972          sec = (now - user->jointime) % 60;
00973          if ( !concise )
00974             ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %02d:%02d:%02d\n",
00975                user->user_no,
00976                S_OR(user->chan->cid.cid_num, "<unknown>"),
00977                S_OR(user->chan->cid.cid_name, "<no name>"),
00978                user->chan->name,
00979                user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
00980                user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
00981                user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
00982                istalking(user->talking), hr, min, sec); 
00983          else 
00984             ast_cli(fd, "%d!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
00985                user->user_no,
00986                S_OR(user->chan->cid.cid_num, ""),
00987                S_OR(user->chan->cid.cid_name, ""),
00988                user->chan->name,
00989                user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
00990                user->userflags  & CONFFLAG_MONITOR ? "1" : "",
00991                user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)  ? "1" : "",
00992                user->talking, hr, min, sec);
00993          
00994       }
00995       if ( !concise )
00996          ast_cli(fd,"%d users in that conference.\n",cnf->users);
00997       AST_LIST_UNLOCK(&confs);
00998       return RESULT_SUCCESS;
00999    } else 
01000       return RESULT_SHOWUSAGE;
01001    ast_log(LOG_DEBUG, "Cmdline: %s\n", cmdline);
01002    admin_exec(NULL, cmdline);
01003 
01004    return 0;
01005 }

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

Definition at line 3137 of file app_meetme.c.

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

Referenced by action_meetmemute(), and action_meetmeunmute().

03138 {
03139    struct ast_conference *conf;
03140    struct ast_conf_user *user;
03141    const char *confid = astman_get_header(m, "Meetme");
03142    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
03143    int userno;
03144 
03145    if (ast_strlen_zero(confid)) {
03146       astman_send_error(s, m, "Meetme conference not specified");
03147       return 0;
03148    }
03149 
03150    if (ast_strlen_zero(userid)) {
03151       astman_send_error(s, m, "Meetme user number not specified");
03152       return 0;
03153    }
03154 
03155    userno = strtoul(userid, &userid, 10);
03156 
03157    if (*userid) {
03158       astman_send_error(s, m, "Invalid user number");
03159       return 0;
03160    }
03161 
03162    /* Look in the conference list */
03163    AST_LIST_LOCK(&confs);
03164    AST_LIST_TRAVERSE(&confs, conf, list) {
03165       if (!strcmp(confid, conf->confno))
03166          break;
03167    }
03168 
03169    if (!conf) {
03170       AST_LIST_UNLOCK(&confs);
03171       astman_send_error(s, m, "Meetme conference does not exist");
03172       return 0;
03173    }
03174 
03175    AST_LIST_TRAVERSE(&conf->userlist, user, list)
03176       if (user->user_no == userno)
03177          break;
03178 
03179    if (!user) {
03180       AST_LIST_UNLOCK(&confs);
03181       astman_send_error(s, m, "User number not found");
03182       return 0;
03183    }
03184 
03185    if (mute)
03186       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
03187    else
03188       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);  /* request user unmuting */
03189 
03190    AST_LIST_UNLOCK(&confs);
03191 
03192    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);
03193 
03194    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
03195    return 0;
03196 }

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

Callback for devicestate providers.

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

03274 {
03275    struct ast_conference *conf;
03276 
03277    /* Find conference */
03278    AST_LIST_LOCK(&confs);
03279    AST_LIST_TRAVERSE(&confs, conf, list) {
03280       if (!strcmp(data, conf->confno))
03281          break;
03282    }
03283    AST_LIST_UNLOCK(&confs);
03284    if (!conf)
03285       return AST_DEVICE_INVALID;
03286 
03287 
03288    /* SKREP to fill */
03289    if (!conf->users)
03290       return AST_DEVICE_NOT_INUSE;
03291 
03292    return AST_DEVICE_INUSE;
03293 }

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

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

04507 {
04508    struct sla_ringing_trunk *ringing_trunk;
04509 
04510    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
04511       return NULL;
04512    
04513    ringing_trunk->trunk = trunk;
04514    ringing_trunk->ring_begin = ast_tvnow();
04515 
04516    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
04517 
04518    ast_mutex_lock(&sla.lock);
04519    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
04520    ast_mutex_unlock(&sla.lock);
04521 
04522    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04523 
04524    return ringing_trunk;
04525 }

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

Definition at line 3208 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.

03209 {
03210    struct ast_conference *cnf = args;
03211    struct ast_frame *f=NULL;
03212    int flags;
03213    struct ast_filestream *s=NULL;
03214    int res=0;
03215    int x;
03216    const char *oldrecordingfilename = NULL;
03217 
03218    if (!cnf || !cnf->lchan) {
03219       pthread_exit(0);
03220    }
03221 
03222    ast_stopstream(cnf->lchan);
03223    flags = O_CREAT|O_TRUNC|O_WRONLY;
03224 
03225 
03226    cnf->recording = MEETME_RECORD_ACTIVE;
03227    while (ast_waitfor(cnf->lchan, -1) > -1) {
03228       if (cnf->recording == MEETME_RECORD_TERMINATE) {
03229          AST_LIST_LOCK(&confs);
03230          AST_LIST_UNLOCK(&confs);
03231          break;
03232       }
03233       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
03234          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
03235          oldrecordingfilename = cnf->recordingfilename;
03236       }
03237       
03238       f = ast_read(cnf->lchan);
03239       if (!f) {
03240          res = -1;
03241          break;
03242       }
03243       if (f->frametype == AST_FRAME_VOICE) {
03244          ast_mutex_lock(&cnf->listenlock);
03245          for (x=0;x<AST_FRAME_BITS;x++) {
03246             /* Free any translations that have occured */
03247             if (cnf->transframe[x]) {
03248                ast_frfree(cnf->transframe[x]);
03249                cnf->transframe[x] = NULL;
03250             }
03251          }
03252          if (cnf->origframe)
03253             ast_frfree(cnf->origframe);
03254          cnf->origframe = ast_frdup(f);
03255          ast_mutex_unlock(&cnf->listenlock);
03256          if (s)
03257             res = ast_writestream(s, f);
03258          if (res) {
03259             ast_frfree(f);
03260             break;
03261          }
03262       }
03263       ast_frfree(f);
03264    }
03265    cnf->recording = MEETME_RECORD_OFF;
03266    if (s)
03267       ast_closestream(s);
03268    
03269    pthread_exit(0);
03270 }

static int reload ( void   )  [static]

Definition at line 5076 of file app_meetme.c.

References load_config().

05077 {
05078    return load_config(1);
05079 }

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

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

03461 {
03462    struct sla_station *station;
03463    struct sla_trunk_ref *trunk_ref;
03464    char conf_name[MAX_CONFNUM];
03465    struct ast_flags conf_flags = { 0 };
03466    struct ast_conference *conf;
03467 
03468    {
03469       struct run_station_args *args = data;
03470       station = args->station;
03471       trunk_ref = args->trunk_ref;
03472       ast_mutex_lock(args->cond_lock);
03473       ast_cond_signal(args->cond);
03474       ast_mutex_unlock(args->cond_lock);
03475       /* args is no longer valid here. */
03476    }
03477 
03478    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
03479    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
03480    ast_set_flag(&conf_flags, 
03481       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
03482    answer_trunk_chan(trunk_ref->chan);
03483    conf = build_conf(conf_name, "", "", 0, 0, 1);
03484    if (conf) {
03485       conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
03486       dispose_conf(conf);
03487       conf = NULL;
03488    }
03489    trunk_ref->chan = NULL;
03490    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
03491       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
03492       strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
03493       admin_exec(NULL, conf_name);
03494       trunk_ref->trunk->hold_stations = 0;
03495       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03496    }
03497 
03498    ast_dial_join(station->dial);
03499    ast_dial_destroy(station->dial);
03500    station->dial = NULL;
03501 
03502    return NULL;
03503 }

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

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

01502 {
01503    manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
01504          "Channel: %s\r\n"
01505          "Uniqueid: %s\r\n"
01506          "Meetme: %s\r\n"
01507          "Usernum: %d\r\n"
01508          "Status: %s\r\n",
01509          chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
01510 }

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

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

Referenced by conf_run().

01513 {
01514    int last_talking = user->talking;
01515    if (last_talking == talking)
01516       return;
01517 
01518    user->talking = talking;
01519 
01520    if (monitor) {
01521       /* Check if talking state changed. Take care of -1 which means unmonitored */
01522       int was_talking = (last_talking > 0);
01523       int now_talking = (talking > 0);
01524       if (was_talking != now_talking) {
01525          send_talking_event(chan, conf, user, now_talking);
01526       }
01527    }
01528 }

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

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

04810 {
04811    struct sla_trunk *trunk;
04812    struct sla_trunk_ref *trunk_ref;
04813    struct sla_station_ref *station_ref;
04814    char *trunk_name, *options, *cur;
04815 
04816    options = ast_strdupa(var->value);
04817    trunk_name = strsep(&options, ",");
04818    
04819    AST_RWLIST_RDLOCK(&sla_trunks);
04820    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04821       if (!strcasecmp(trunk->name, trunk_name))
04822          break;
04823    }
04824 
04825    AST_RWLIST_UNLOCK(&sla_trunks);
04826    if (!trunk) {
04827       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
04828       return;
04829    }
04830    if (!(trunk_ref = create_trunk_ref(trunk)))
04831       return;
04832    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
04833 
04834    while ((cur = strsep(&options, ","))) {
04835       char *name, *value = cur;
04836       name = strsep(&value, "=");
04837       if (!strcasecmp(name, "ringtimeout")) {
04838          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
04839             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
04840                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04841             trunk_ref->ring_timeout = 0;
04842          }
04843       } else if (!strcasecmp(name, "ringdelay")) {
04844          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
04845             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
04846                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04847             trunk_ref->ring_delay = 0;
04848          }
04849       } else {
04850          ast_log(LOG_WARNING, "Invalid option '%s' for "
04851             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
04852       }
04853    }
04854 
04855    if (!(station_ref = sla_create_station_ref(station))) {
04856       free(trunk_ref);
04857       return;
04858    }
04859    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
04860    AST_RWLIST_WRLOCK(&sla_trunks);
04861    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
04862    AST_RWLIST_UNLOCK(&sla_trunks);
04863    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
04864 }

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

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

04867 {
04868    struct sla_station *station;
04869    struct ast_variable *var;
04870    const char *dev;
04871 
04872    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
04873       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
04874       return -1;
04875    }
04876 
04877    if (!(station = ast_calloc(1, sizeof(*station))))
04878       return -1;
04879    if (ast_string_field_init(station, 32)) {
04880       free(station);
04881       return -1;
04882    }
04883 
04884    ast_string_field_set(station, name, cat);
04885    ast_string_field_set(station, device, dev);
04886 
04887    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04888       if (!strcasecmp(var->name, "trunk"))
04889          sla_add_trunk_to_station(station, var);
04890       else if (!strcasecmp(var->name, "autocontext"))
04891          ast_string_field_set(station, autocontext, var->value);
04892       else if (!strcasecmp(var->name, "ringtimeout")) {
04893          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
04894             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
04895                var->value, station->name);
04896             station->ring_timeout = 0;
04897          }
04898       } else if (!strcasecmp(var->name, "ringdelay")) {
04899          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
04900             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
04901                var->value, station->name);
04902             station->ring_delay = 0;
04903          }
04904       } else if (!strcasecmp(var->name, "hold")) {
04905          if (!strcasecmp(var->value, "private"))
04906             station->hold_access = SLA_HOLD_PRIVATE;
04907          else if (!strcasecmp(var->value, "open"))
04908             station->hold_access = SLA_HOLD_OPEN;
04909          else {
04910             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
04911                var->value, station->name);
04912          }
04913 
04914       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
04915          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
04916             var->name, var->lineno, SLA_CONFIG_FILE);
04917       }
04918    }
04919 
04920    if (!ast_strlen_zero(station->autocontext)) {
04921       struct ast_context *context;
04922       struct sla_trunk_ref *trunk_ref;
04923       context = ast_context_find_or_create(NULL, station->autocontext, sla_registrar);
04924       if (!context) {
04925          ast_log(LOG_ERROR, "Failed to automatically find or create "
04926             "context '%s' for SLA!\n", station->autocontext);
04927          destroy_station(station);
04928          return -1;
04929       }
04930       /* The extension for when the handset goes off-hook.
04931        * exten => station1,1,SLAStation(station1) */
04932       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
04933          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
04934          ast_log(LOG_ERROR, "Failed to automatically create extension "
04935             "for trunk '%s'!\n", station->name);
04936          destroy_station(station);
04937          return -1;
04938       }
04939       AST_RWLIST_RDLOCK(&sla_trunks);
04940       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04941          char exten[AST_MAX_EXTENSION];
04942          char hint[AST_MAX_APP];
04943          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04944          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04945          /* Extension for this line button 
04946           * exten => station1_line1,1,SLAStation(station1_line1) */
04947          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
04948             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
04949             ast_log(LOG_ERROR, "Failed to automatically create extension "
04950                "for trunk '%s'!\n", station->name);
04951             destroy_station(station);
04952             return -1;
04953          }
04954          /* Hint for this line button 
04955           * exten => station1_line1,hint,SLA:station1_line1 */
04956          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
04957             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
04958             ast_log(LOG_ERROR, "Failed to automatically create hint "
04959                "for trunk '%s'!\n", station->name);
04960             destroy_station(station);
04961             return -1;
04962          }
04963       }
04964       AST_RWLIST_UNLOCK(&sla_trunks);
04965    }
04966 
04967    AST_RWLIST_WRLOCK(&sla_stations);
04968    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
04969    AST_RWLIST_UNLOCK(&sla_stations);
04970 
04971    return 0;
04972 }

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

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

04732 {
04733    struct sla_trunk *trunk;
04734    struct ast_variable *var;
04735    const char *dev;
04736 
04737    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
04738       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
04739       return -1;
04740    }
04741 
04742    if (sla_check_device(dev)) {
04743       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
04744          cat, dev);
04745       return -1;
04746    }
04747 
04748    if (!(trunk = ast_calloc(1, sizeof(*trunk))))
04749       return -1;
04750    if (ast_string_field_init(trunk, 32)) {
04751       free(trunk);
04752       return -1;
04753    }
04754 
04755    ast_string_field_set(trunk, name, cat);
04756    ast_string_field_set(trunk, device, dev);
04757 
04758    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04759       if (!strcasecmp(var->name, "autocontext"))
04760          ast_string_field_set(trunk, autocontext, var->value);
04761       else if (!strcasecmp(var->name, "ringtimeout")) {
04762          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
04763             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
04764                var->value, trunk->name);
04765             trunk->ring_timeout = 0;
04766          }
04767       } else if (!strcasecmp(var->name, "barge"))
04768          trunk->barge_disabled = ast_false(var->value);
04769       else if (!strcasecmp(var->name, "hold")) {
04770          if (!strcasecmp(var->value, "private"))
04771             trunk->hold_access = SLA_HOLD_PRIVATE;
04772          else if (!strcasecmp(var->value, "open"))
04773             trunk->hold_access = SLA_HOLD_OPEN;
04774          else {
04775             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
04776                var->value, trunk->name);
04777          }
04778       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
04779          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
04780             var->name, var->lineno, SLA_CONFIG_FILE);
04781       }
04782    }
04783 
04784    if (!ast_strlen_zero(trunk->autocontext)) {
04785       struct ast_context *context;
04786       context = ast_context_find_or_create(NULL, trunk->autocontext, sla_registrar);
04787       if (!context) {
04788          ast_log(LOG_ERROR, "Failed to automatically find or create "
04789             "context '%s' for SLA!\n", trunk->autocontext);
04790          destroy_trunk(trunk);
04791          return -1;
04792       }
04793       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
04794          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
04795          ast_log(LOG_ERROR, "Failed to automatically create extension "
04796             "for trunk '%s'!\n", trunk->name);
04797          destroy_trunk(trunk);
04798          return -1;
04799       }
04800    }
04801 
04802    AST_RWLIST_WRLOCK(&sla_trunks);
04803    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
04804    AST_RWLIST_UNLOCK(&sla_trunks);
04805 
04806    return 0;
04807 }

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

04078 {
04079    struct sla_station *station;
04080    int res = 0;
04081 
04082    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04083       struct sla_ringing_trunk *ringing_trunk;
04084       int time_left;
04085 
04086       /* Ignore stations already ringing */
04087       if (sla_check_ringing_station(station))
04088          continue;
04089 
04090       /* Ignore stations already on a call */
04091       if (sla_check_inuse_station(station))
04092          continue;
04093 
04094       /* Ignore stations that don't have one of their trunks ringing */
04095       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
04096          continue;
04097 
04098       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
04099          continue;
04100 
04101       /* If there is no time left, then the station needs to start ringing.
04102        * Return non-zero so that an event will be queued up an event to 
04103        * make that happen. */
04104       if (time_left <= 0) {
04105          res = 1;
04106          continue;
04107       }
04108 
04109       if (time_left < *timeout)
04110          *timeout = time_left;
04111    }
04112 
04113    return res;
04114 }

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

03995 {
03996    struct sla_ringing_trunk *ringing_trunk;
03997    struct sla_ringing_station *ringing_station;
03998    int res = 0;
03999 
04000    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04001       unsigned int ring_timeout = 0;
04002       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
04003       struct sla_trunk_ref *trunk_ref;
04004 
04005       /* If there are any ring timeouts specified for a specific trunk
04006        * on the station, then use the highest per-trunk ring timeout.
04007        * Otherwise, use the ring timeout set for the entire station. */
04008       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04009          struct sla_station_ref *station_ref;
04010          int trunk_time_elapsed, trunk_time_left;
04011 
04012          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04013             if (ringing_trunk->trunk == trunk_ref->trunk)
04014                break;
04015          }
04016          if (!ringing_trunk)
04017             continue;
04018 
04019          /* If there is a trunk that is ringing without a timeout, then the
04020           * only timeout that could matter is a global station ring timeout. */
04021          if (!trunk_ref->ring_timeout)
04022             break;
04023 
04024          /* This trunk on this station is ringing and has a timeout.
04025           * However, make sure this trunk isn't still ringing from a
04026           * previous timeout.  If so, don't consider it. */
04027          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
04028             if (station_ref->station == ringing_station->station)
04029                break;
04030          }
04031          if (station_ref)
04032             continue;
04033 
04034          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04035          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
04036          if (trunk_time_left > final_trunk_time_left)
04037             final_trunk_time_left = trunk_time_left;
04038       }
04039 
04040       /* No timeout was found for ringing trunks, and no timeout for the entire station */
04041       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
04042          continue;
04043 
04044       /* Compute how much time is left for a global station timeout */
04045       if (ringing_station->station->ring_timeout) {
04046          ring_timeout = ringing_station->station->ring_timeout;
04047          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
04048          time_left = (ring_timeout * 1000) - time_elapsed;
04049       }
04050 
04051       /* If the time left based on the per-trunk timeouts is smaller than the
04052        * global station ring timeout, use that. */
04053       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
04054          time_left = final_trunk_time_left;
04055 
04056       /* If there is no time left, the station needs to stop ringing */
04057       if (time_left <= 0) {
04058          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
04059          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
04060          res = 1;
04061          continue;
04062       }
04063 
04064       /* There is still some time left for this station to ring, so save that
04065        * timeout if it is the first event scheduled to occur */
04066       if (time_left < *timeout)
04067          *timeout = time_left;
04068    }
04069    AST_LIST_TRAVERSE_SAFE_END
04070 
04071    return res;
04072 }

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

03965 {
03966    struct sla_ringing_trunk *ringing_trunk;
03967    int res = 0;
03968 
03969    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03970       int time_left, time_elapsed;
03971       if (!ringing_trunk->trunk->ring_timeout)
03972          continue;
03973       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03974       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
03975       if (time_left <= 0) {
03976          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
03977          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03978          sla_stop_ringing_trunk(ringing_trunk);
03979          res = 1;
03980          continue;
03981       }
03982       if (time_left < *timeout)
03983          *timeout = time_left;
03984    }
03985    AST_LIST_TRAVERSE_SAFE_END
03986 
03987    return res;
03988 }

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

03431 {
03432    struct sla_station *station;
03433    struct sla_trunk_ref *trunk_ref;
03434 
03435    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
03436       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03437          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
03438             || trunk_ref == exclude)
03439             continue;
03440          trunk_ref->state = state;
03441          ast_device_state_changed("SLA:%s_%s", station->name, trunk->name);
03442          break;
03443       }
03444    }
03445 }

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

Definition at line 4718 of file app_meetme.c.

References ast_strdupa, and ast_strlen_zero().

Referenced by sla_build_trunk().

04719 {
04720    char *tech, *tech_data;
04721 
04722    tech_data = ast_strdupa(device);
04723    tech = strsep(&tech_data, "/");
04724 
04725    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
04726       return -1;
04727 
04728    return 0;
04729 }

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

03713 {
03714    struct sla_failed_station *failed_station;
03715    int res = 0;
03716 
03717    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
03718       if (station != failed_station->station)
03719          continue;
03720       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
03721          AST_LIST_REMOVE_CURRENT(&sla.failed_stations, entry);
03722          free(failed_station);
03723          break;
03724       }
03725       res = 1;
03726    }
03727    AST_LIST_TRAVERSE_SAFE_END
03728 
03729    return res;
03730 }

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

Check to see if a station is in use.

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

03799 {
03800    struct sla_trunk_ref *trunk_ref;
03801 
03802    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03803       if (trunk_ref->chan)
03804          return 1;
03805    }
03806 
03807    return 0;
03808 }

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

03698 {
03699    struct sla_ringing_station *ringing_station;
03700 
03701    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
03702       if (station == ringing_station->station)
03703          return 1;
03704    }
03705 
03706    return 0;
03707 }

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

03830 {
03831    struct sla_trunk_ref *trunk_ref;
03832    unsigned int delay = UINT_MAX;
03833    int time_left, time_elapsed;
03834 
03835    if (!ringing_trunk)
03836       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
03837    else
03838       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
03839 
03840    if (!ringing_trunk || !trunk_ref)
03841       return delay;
03842 
03843    /* If this station has a ring delay specific to the highest priority
03844     * ringing trunk, use that.  Otherwise, use the ring delay specified
03845     * globally for the station. */
03846    delay = trunk_ref->ring_delay;
03847    if (!delay)
03848       delay = station->ring_delay;
03849    if (!delay)
03850       return INT_MAX;
03851 
03852    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03853    time_left = (delay * 1000) - time_elapsed;
03854 
03855    return time_left;
03856 }

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

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

03353 {
03354    struct sla_station_ref *station_ref;
03355    struct sla_trunk_ref *trunk_ref;
03356 
03357    /* For each station that has this call on hold, check for private hold. */
03358    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03359       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03360          if (trunk_ref->trunk != trunk || station_ref->station == station)
03361             continue;
03362          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03363             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03364             return 1;
03365          return 0;
03366       }
03367    }
03368 
03369    return 0;
03370 }

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

03565 {
03566    struct sla_station_ref *timed_out_station;
03567 
03568    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
03569       if (station == timed_out_station->station)
03570          return 1;
03571    }
03572 
03573    return 0;
03574 }

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

04329 {
04330    struct sla_trunk_ref *trunk_ref = NULL;
04331 
04332    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04333       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
04334          break;
04335    }
04336 
04337    return trunk_ref;
04338 }

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

03586 {
03587    struct sla_trunk_ref *s_trunk_ref;
03588    struct sla_ringing_trunk *ringing_trunk = NULL;
03589 
03590    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
03591       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03592          /* Make sure this is the trunk we're looking for */
03593          if (s_trunk_ref->trunk != ringing_trunk->trunk)
03594             continue;
03595 
03596          /* This trunk on the station is ringing.  But, make sure this station
03597           * didn't already time out while this trunk was ringing. */
03598          if (sla_check_timed_out_station(ringing_trunk, station))
03599             continue;
03600 
03601          if (remove)
03602             AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03603 
03604          if (trunk_ref)
03605             *trunk_ref = s_trunk_ref;
03606 
03607          break;
03608       }
03609       AST_LIST_TRAVERSE_SAFE_END
03610    
03611       if (ringing_trunk)
03612          break;
03613    }
03614 
03615    return ringing_trunk;
03616 }

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

Definition at line 3416 of file app_meetme.c.

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

Referenced by sla_ring_station().

03417 {
03418    struct sla_ringing_station *ringing_station;
03419 
03420    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
03421       return NULL;
03422 
03423    ringing_station->station = station;
03424    ringing_station->ring_begin = ast_tvnow();
03425 
03426    return ringing_station;
03427 }

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

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

03405 {
03406    struct sla_station_ref *station_ref;
03407 
03408    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
03409       return NULL;
03410 
03411    station_ref->station = station;
03412 
03413    return station_ref;
03414 }

static void sla_destroy ( void   )  [static]

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

04689 {
04690    struct sla_trunk *trunk;
04691    struct sla_station *station;
04692 
04693    AST_RWLIST_WRLOCK(&sla_trunks);
04694    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
04695       destroy_trunk(trunk);
04696    AST_RWLIST_UNLOCK(&sla_trunks);
04697 
04698    AST_RWLIST_WRLOCK(&sla_stations);
04699    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
04700       destroy_station(station);
04701    AST_RWLIST_UNLOCK(&sla_stations);
04702 
04703    if (sla.thread != AST_PTHREADT_NULL) {
04704       ast_mutex_lock(&sla.lock);
04705       sla.stop = 1;
04706       ast_cond_signal(&sla.cond);
04707       ast_mutex_unlock(&sla.lock);
04708       pthread_join(sla.thread, NULL);
04709    }
04710 
04711    /* Drop any created contexts from the dialplan */
04712    ast_context_destroy(NULL, sla_registrar);
04713 
04714    ast_mutex_destroy(&sla.lock);
04715    ast_cond_destroy(&sla.cond);
04716 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 3555 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

03556 {
03557    sla_queue_event(SLA_EVENT_DIAL_STATE);
03558 }

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

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

Referenced by sla_station_exec().

03340 {
03341    struct sla_station *station = NULL;
03342 
03343    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03344       if (!strcasecmp(station->name, name))
03345          break;
03346    }
03347 
03348    return station;
03349 }

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

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

Referenced by sla_trunk_exec().

03325 {
03326    struct sla_trunk *trunk = NULL;
03327 
03328    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03329       if (!strcasecmp(trunk->name, name))
03330          break;
03331    }
03332 
03333    return trunk;
03334 }

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

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

03812 {
03813    struct sla_trunk_ref *trunk_ref = NULL;
03814 
03815    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03816       if (trunk_ref->trunk == trunk)
03817          break;
03818    }
03819 
03820    return trunk_ref;
03821 }

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

03381 {
03382    struct sla_trunk_ref *trunk_ref = NULL;
03383 
03384    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03385       if (strcasecmp(trunk_ref->trunk->name, name))
03386          continue;
03387 
03388       if ( (trunk_ref->trunk->barge_disabled 
03389          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
03390          (trunk_ref->trunk->hold_stations 
03391          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
03392          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
03393          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
03394       {
03395          trunk_ref = NULL;
03396       }
03397 
03398       break;
03399    }
03400 
03401    return trunk_ref;
03402 }

static void sla_handle_dial_state_event ( void   )  [static]

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

03619 {
03620    struct sla_ringing_station *ringing_station;
03621 
03622    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03623       struct sla_trunk_ref *s_trunk_ref = NULL;
03624       struct sla_ringing_trunk *ringing_trunk = NULL;
03625       struct run_station_args args;
03626       enum ast_dial_result dial_res;
03627       pthread_attr_t attr;
03628       pthread_t dont_care;
03629       ast_mutex_t cond_lock;
03630       ast_cond_t cond;
03631 
03632       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
03633       case AST_DIAL_RESULT_HANGUP:
03634       case AST_DIAL_RESULT_INVALID:
03635       case AST_DIAL_RESULT_FAILED:
03636       case AST_DIAL_RESULT_TIMEOUT:
03637       case AST_DIAL_RESULT_UNANSWERED:
03638          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03639          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
03640          break;
03641       case AST_DIAL_RESULT_ANSWERED:
03642          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03643          /* Find the appropriate trunk to answer. */
03644          ast_mutex_lock(&sla.lock);
03645          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
03646          ast_mutex_unlock(&sla.lock);
03647          if (!ringing_trunk) {
03648             ast_log(LOG_DEBUG, "Found no ringing trunk for station '%s' to answer!\n",
03649                ringing_station->station->name);
03650             break;
03651          }
03652          /* Track the channel that answered this trunk */
03653          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
03654          /* Actually answer the trunk */
03655          answer_trunk_chan(ringing_trunk->trunk->chan);
03656          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
03657          /* Now, start a thread that will connect this station to the trunk.  The rest of
03658           * the code here sets up the thread and ensures that it is able to save the arguments
03659           * before they are no longer valid since they are allocated on the stack. */
03660          args.trunk_ref = s_trunk_ref;
03661          args.station = ringing_station->station;
03662          args.cond = &cond;
03663          args.cond_lock = &cond_lock;
03664          free(ringing_trunk);
03665          free(ringing_station);
03666          ast_mutex_init(&cond_lock);
03667          ast_cond_init(&cond, NULL);
03668          pthread_attr_init(&attr);
03669          pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
03670          ast_mutex_lock(&cond_lock);
03671          ast_pthread_create_background(&dont_care, &attr, run_station, &args);
03672          ast_cond_wait(&cond, &cond_lock);
03673          ast_mutex_unlock(&cond_lock);
03674          ast_mutex_destroy(&cond_lock);
03675          ast_cond_destroy(&cond);
03676          pthread_attr_destroy(&attr);
03677          break;
03678       case AST_DIAL_RESULT_TRYING:
03679       case AST_DIAL_RESULT_RINGING:
03680       case AST_DIAL_RESULT_PROGRESS:
03681       case AST_DIAL_RESULT_PROCEEDING:
03682          break;
03683       }
03684       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
03685          /* Queue up reprocessing ringing trunks, and then ringing stations again */
03686          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
03687          sla_queue_event(SLA_EVENT_DIAL_STATE);
03688          break;
03689       }
03690    }
03691    AST_LIST_TRAVERSE_SAFE_END
03692 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

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

03941 {
03942    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
03943    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
03944    ast_device_state_changed("SLA:%s_%s", 
03945       event->station->name, event->trunk_ref->trunk->name);
03946    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
03947       INACTIVE_TRUNK_REFS, event->trunk_ref);
03948 
03949    if (event->trunk_ref->trunk->active_stations == 1) {
03950       /* The station putting it on hold is the only one on the call, so start
03951        * Music on hold to the trunk. */
03952       event->trunk_ref->trunk->on_hold = 1;
03953       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
03954    }
03955 
03956    ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
03957    event->trunk_ref->chan = NULL;
03958 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 3930 of file app_meetme.c.

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

Referenced by sla_thread().

03931 {
03932    ast_mutex_lock(&sla.lock);
03933    sla_ring_stations();
03934    ast_mutex_unlock(&sla.lock);
03935 
03936    /* Find stations that shouldn't be ringing anymore. */
03937    sla_hangup_stations();
03938 }

static void sla_hangup_stations ( void   )  [static]

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

03903 {
03904    struct sla_trunk_ref *trunk_ref;
03905    struct sla_ringing_station *ringing_station;
03906 
03907    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03908       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03909          struct sla_ringing_trunk *ringing_trunk;
03910          ast_mutex_lock(&sla.lock);
03911          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03912             if (trunk_ref->trunk == ringing_trunk->trunk)
03913                break;
03914          }
03915          ast_mutex_unlock(&sla.lock);
03916          if (ringing_trunk)
03917             break;
03918       }
03919       if (!trunk_ref) {
03920          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03921          ast_dial_join(ringing_station->station->dial);
03922          ast_dial_destroy(ringing_station->station->dial);
03923          ringing_station->station->dial = NULL;
03924          free(ringing_station);
03925       }
03926    }
03927    AST_LIST_TRAVERSE_SAFE_END
03928 }

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

Definition at line 1073 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

01074 {
01075    const char *hold = "Unknown";
01076 
01077    switch (hold_access) {
01078    case SLA_HOLD_OPEN:
01079       hold = "Open";
01080       break;
01081    case SLA_HOLD_PRIVATE:
01082       hold = "Private";
01083    default:
01084       break;
01085    }
01086 
01087    return hold;
01088 }

static int sla_load_config ( void   )  [static]

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

04975 {
04976    struct ast_config *cfg;
04977    const char *cat = NULL;
04978    int res = 0;
04979    const char *val;
04980 
04981    ast_mutex_init(&sla.lock);
04982    ast_cond_init(&sla.cond, NULL);
04983 
04984    if (!(cfg = ast_config_load(SLA_CONFIG_FILE)))
04985       return 0; /* Treat no config as normal */
04986 
04987    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
04988       sla.attempt_callerid = ast_true(val);
04989 
04990    while ((cat = ast_category_browse(cfg, cat)) && !res) {
04991       const char *type;
04992       if (!strcasecmp(cat, "general"))
04993          continue;
04994       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
04995          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
04996             SLA_CONFIG_FILE);
04997          continue;
04998       }
04999       if (!strcasecmp(type, "trunk"))
05000          res = sla_build_trunk(cfg, cat);
05001       else if (!strcasecmp(type, "station"))
05002          res = sla_build_station(cfg, cat);
05003       else {
05004          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
05005             SLA_CONFIG_FILE, type);
05006       }
05007    }
05008 
05009    ast_config_destroy(cfg);
05010 
05011    if (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations))
05012       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
05013 
05014    return res;
05015 }

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

04119 {
04120    unsigned int timeout = UINT_MAX;
04121    struct timeval tv;
04122    unsigned int change_made = 0;
04123 
04124    /* Check for ring timeouts on ringing trunks */
04125    if (sla_calc_trunk_timeouts(&timeout))
04126       change_made = 1;
04127 
04128    /* Check for ring timeouts on ringing stations */
04129    if (sla_calc_station_timeouts(&timeout))
04130       change_made = 1;
04131 
04132    /* Check for station ring delays */
04133    if (sla_calc_station_delays(&timeout))
04134       change_made = 1;
04135 
04136    /* queue reprocessing of ringing trunks */
04137    if (change_made)
04138       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
04139 
04140    /* No timeout */
04141    if (timeout == UINT_MAX)
04142       return 0;
04143 
04144    if (ts) {
04145       tv = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
04146       ts->tv_sec = tv.tv_sec;
04147       ts->tv_nsec = tv.tv_usec * 1000;
04148    }
04149 
04150    return 1;
04151 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

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

01368 {
01369    sla_queue_event_full(type, NULL, NULL, 1);
01370 }

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

01375 {
01376    struct sla_station *station;
01377    struct sla_trunk_ref *trunk_ref = NULL;
01378    char *trunk_name;
01379 
01380    trunk_name = ast_strdupa(conf->confno);
01381    strsep(&trunk_name, "_");
01382    if (ast_strlen_zero(trunk_name)) {
01383       ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01384       return;
01385    }
01386 
01387    AST_RWLIST_RDLOCK(&sla_stations);
01388    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01389       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01390          if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01391             break;
01392       }
01393       if (trunk_ref)
01394          break;
01395    }
01396    AST_RWLIST_UNLOCK(&sla_stations);
01397 
01398    if (!trunk_ref) {
01399       ast_log(LOG_DEBUG, "Trunk not found for event!\n");
01400       return;
01401    }
01402 
01403    sla_queue_event_full(type, trunk_ref, station, 1);
01404 }

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

01337 {
01338    struct sla_event *event;
01339 
01340    if (sla.thread == AST_PTHREADT_NULL) {
01341       return;
01342    }
01343 
01344    if (!(event = ast_calloc(1, sizeof(*event))))
01345       return;
01346 
01347    event->type = type;
01348    event->trunk_ref = trunk_ref;
01349    event->station = station;
01350 
01351    if (!lock) {
01352       AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01353       return;
01354    }
01355 
01356    ast_mutex_lock(&sla.lock);
01357    AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01358    ast_cond_signal(&sla.cond);
01359    ast_mutex_unlock(&sla.lock);
01360 }

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1362 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01363 {
01364    sla_queue_event_full(type, NULL, NULL, 0);
01365 }

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

03736 {
03737    char *tech, *tech_data;
03738    struct ast_dial *dial;
03739    struct sla_ringing_station *ringing_station;
03740    const char *cid_name = NULL, *cid_num = NULL;
03741    enum ast_dial_result res;
03742 
03743    if (!(dial = ast_dial_create()))
03744       return -1;
03745 
03746    ast_dial_set_state_callback(dial, sla_dial_state_callback);
03747    tech_data = ast_strdupa(station->device);
03748    tech = strsep(&tech_data, "/");
03749 
03750    if (ast_dial_append(dial, tech, tech_data) == -1) {
03751       ast_dial_destroy(dial);
03752       return -1;
03753    }
03754 
03755    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
03756       cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
03757       free(ringing_trunk->trunk->chan->cid.cid_name);
03758       ringing_trunk->trunk->chan->cid.cid_name = NULL;
03759    }
03760    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
03761       cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
03762       free(ringing_trunk->trunk->chan->cid.cid_num);
03763       ringing_trunk->trunk->chan->cid.cid_num = NULL;
03764    }
03765 
03766    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
03767    
03768    if (cid_name)
03769       ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
03770    if (cid_num)
03771       ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
03772    
03773    if (res != AST_DIAL_RESULT_TRYING) {
03774       struct sla_failed_station *failed_station;
03775       ast_dial_destroy(dial);
03776       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
03777          return -1;
03778       failed_station->station = station;
03779       failed_station->last_try = ast_tvnow();
03780       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
03781       return -1;
03782    }
03783    if (!(ringing_station = sla_create_ringing_station(station))) {
03784       ast_dial_join(dial);
03785       ast_dial_destroy(dial);
03786       return -1;
03787    }
03788 
03789    station->dial = dial;
03790 
03791    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
03792 
03793    return 0;
03794 }

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

03862 {
03863    struct sla_station_ref *station_ref;
03864    struct sla_ringing_trunk *ringing_trunk;
03865 
03866    /* Make sure that every station that uses at least one of the ringing
03867     * trunks, is ringing. */
03868    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03869       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
03870          int time_left;
03871 
03872          /* Is this station already ringing? */
03873          if (sla_check_ringing_station(station_ref->station))
03874             continue;
03875 
03876          /* Is this station already in a call? */
03877          if (sla_check_inuse_station(station_ref->station))
03878             continue;
03879 
03880          /* Did we fail to dial this station earlier?  If so, has it been
03881           * a minute since we tried? */
03882          if (sla_check_failed_station(station_ref->station))
03883             continue;
03884 
03885          /* If this station already timed out while this trunk was ringing,
03886           * do not dial it again for this ringing trunk. */
03887          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
03888             continue;
03889 
03890          /* Check for a ring delay in progress */
03891          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
03892          if (time_left != INT_MAX && time_left > 0)
03893             continue;
03894 
03895          /* It is time to make this station begin to ring.  Do it! */
03896          sla_ring_station(ringing_trunk, station_ref->station);
03897       }
03898    }
03899    /* Now, all of the stations that should be ringing, are ringing. */
03900 }

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

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

01151 {
01152    const struct sla_station *station;
01153 
01154    ast_cli(fd, "\n" 
01155                "=============================================================\n"
01156                "=== Configured SLA Stations =================================\n"
01157                "=============================================================\n"
01158                "===\n");
01159    AST_RWLIST_RDLOCK(&sla_stations);
01160    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01161       struct sla_trunk_ref *trunk_ref;
01162       char ring_timeout[16] = "(none)";
01163       char ring_delay[16] = "(none)";
01164       if (station->ring_timeout) {
01165          snprintf(ring_timeout, sizeof(ring_timeout), 
01166             "%u", station->ring_timeout);
01167       }
01168       if (station->ring_delay) {
01169          snprintf(ring_delay, sizeof(ring_delay), 
01170             "%u", station->ring_delay);
01171       }
01172       ast_cli(fd, "=== ---------------------------------------------------------\n"
01173                   "=== Station Name:    %s\n"
01174                   "=== ==> Device:      %s\n"
01175                   "=== ==> AutoContext: %s\n"
01176                   "=== ==> RingTimeout: %s\n"
01177                   "=== ==> RingDelay:   %s\n"
01178                   "=== ==> HoldAccess:  %s\n"
01179                   "=== ==> Trunks ...\n",
01180                   station->name, station->device,
01181                   S_OR(station->autocontext, "(none)"), 
01182                   ring_timeout, ring_delay,
01183                   sla_hold_str(station->hold_access));
01184       AST_RWLIST_RDLOCK(&sla_trunks);
01185       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01186          if (trunk_ref->ring_timeout) {
01187             snprintf(ring_timeout, sizeof(ring_timeout),
01188                "%u", trunk_ref->ring_timeout);
01189          } else
01190             strcpy(ring_timeout, "(none)");
01191          if (trunk_ref->ring_delay) {
01192             snprintf(ring_delay, sizeof(ring_delay),
01193                "%u", trunk_ref->ring_delay);
01194          } else
01195             strcpy(ring_delay, "(none)");
01196          ast_cli(fd, "===    ==> Trunk Name: %s\n"
01197                      "===       ==> State:       %s\n"
01198                      "===       ==> RingTimeout: %s\n"
01199                      "===       ==> RingDelay:   %s\n",
01200                      trunk_ref->trunk->name,
01201                      trunkstate2str(trunk_ref->state),
01202                      ring_timeout, ring_delay);
01203       }
01204       AST_RWLIST_UNLOCK(&sla_trunks);
01205       ast_cli(fd, "=== ---------------------------------------------------------\n"
01206                   "===\n");
01207    }
01208    AST_RWLIST_UNLOCK(&sla_stations);
01209    ast_cli(fd, "============================================================\n"
01210                "\n");
01211 
01212    return RESULT_SUCCESS;
01213 }

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

Definition at line 1090 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.

01091 {
01092    const struct sla_trunk *trunk;
01093 
01094    ast_cli(fd, "\n"
01095                "=============================================================\n"
01096                "=== Configured SLA Trunks ===================================\n"
01097                "=============================================================\n"
01098                "===\n");
01099    AST_RWLIST_RDLOCK(&sla_trunks);
01100    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01101       struct sla_station_ref *station_ref;
01102       char ring_timeout[16] = "(none)";
01103       if (trunk->ring_timeout)
01104          snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01105       ast_cli(fd, "=== ---------------------------------------------------------\n"
01106                   "=== Trunk Name:       %s\n"
01107                   "=== ==> Device:       %s\n"
01108                   "=== ==> AutoContext:  %s\n"
01109                   "=== ==> RingTimeout:  %s\n"
01110                   "=== ==> BargeAllowed: %s\n"
01111                   "=== ==> HoldAccess:   %s\n"
01112                   "=== ==> Stations ...\n",
01113                   trunk->name, trunk->device, 
01114                   S_OR(trunk->autocontext, "(none)"), 
01115                   ring_timeout,
01116                   trunk->barge_disabled ? "No" : "Yes",
01117                   sla_hold_str(trunk->hold_access));
01118       AST_RWLIST_RDLOCK(&sla_stations);
01119       AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01120          ast_cli(fd, "===    ==> Station name: %s\n", station_ref->station->name);
01121       AST_RWLIST_UNLOCK(&sla_stations);
01122       ast_cli(fd, "=== ---------------------------------------------------------\n"
01123                   "===\n");
01124    }
01125    AST_RWLIST_UNLOCK(&sla_trunks);
01126    ast_cli(fd, "=============================================================\n"
01127                "\n");
01128 
01129    return RESULT_SUCCESS;
01130 }

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

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

04599 {
04600    char *buf, *station_name, *trunk_name;
04601    struct sla_station *station;
04602    struct sla_trunk_ref *trunk_ref;
04603    int res = AST_DEVICE_INVALID;
04604 
04605    trunk_name = buf = ast_strdupa(data);
04606    station_name = strsep(&trunk_name, "_");
04607 
04608    AST_RWLIST_RDLOCK(&sla_stations);
04609    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04610       if (strcasecmp(station_name, station->name))
04611          continue;
04612       AST_RWLIST_RDLOCK(&sla_trunks);
04613       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04614          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
04615             break;
04616       }
04617       if (!trunk_ref) {
04618          AST_RWLIST_UNLOCK(&sla_trunks);
04619          break;
04620       }
04621       switch (trunk_ref->state) {
04622       case SLA_TRUNK_STATE_IDLE:
04623          res = AST_DEVICE_NOT_INUSE;
04624          break;
04625       case SLA_TRUNK_STATE_RINGING:
04626          res = AST_DEVICE_RINGING;
04627          break;
04628       case SLA_TRUNK_STATE_UP:
04629          res = AST_DEVICE_INUSE;
04630          break;
04631       case SLA_TRUNK_STATE_ONHOLD:
04632       case SLA_TRUNK_STATE_ONHOLD_BYME:
04633          res = AST_DEVICE_ONHOLD;
04634          break;
04635       }
04636       AST_RWLIST_UNLOCK(&sla_trunks);
04637    }
04638    AST_RWLIST_UNLOCK(&sla_stations);
04639 
04640    if (res == AST_DEVICE_INVALID) {
04641       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
04642          trunk_name, station_name);
04643    }
04644 
04645    return res;
04646 }

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

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

04341 {
04342    char *station_name, *trunk_name;
04343    struct sla_station *station;
04344    struct sla_trunk_ref *trunk_ref = NULL;
04345    char conf_name[MAX_CONFNUM];
04346    struct ast_flags conf_flags = { 0 };
04347    struct ast_conference *conf;
04348 
04349    if (ast_strlen_zero(data)) {
04350       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04351       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04352       return 0;
04353    }
04354 
04355    trunk_name = ast_strdupa(data);
04356    station_name = strsep(&trunk_name, "_");
04357 
04358    if (ast_strlen_zero(station_name)) {
04359       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04360       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04361       return 0;
04362    }
04363 
04364    AST_RWLIST_RDLOCK(&sla_stations);
04365    station = sla_find_station(station_name);
04366    AST_RWLIST_UNLOCK(&sla_stations);
04367 
04368    if (!station) {
04369       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
04370       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04371       return 0;
04372    }
04373 
04374    AST_RWLIST_RDLOCK(&sla_trunks);
04375    if (!ast_strlen_zero(trunk_name)) {
04376       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
04377    } else
04378       trunk_ref = sla_choose_idle_trunk(station);
04379    AST_RWLIST_UNLOCK(&sla_trunks);
04380 
04381    if (!trunk_ref) {
04382       if (ast_strlen_zero(trunk_name))
04383          ast_log(LOG_NOTICE, "No trunks available for call.\n");
04384       else {
04385          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
04386             "'%s' due to access controls.\n", trunk_name);
04387       }
04388       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
04389       return 0;
04390    }
04391 
04392    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
04393       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
04394          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04395       else {
04396          trunk_ref->state = SLA_TRUNK_STATE_UP;
04397          ast_device_state_changed("SLA:%s_%s", station->name, trunk_ref->trunk->name);
04398       }
04399    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
04400       struct sla_ringing_trunk *ringing_trunk;
04401 
04402       ast_mutex_lock(&sla.lock);
04403       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04404          if (ringing_trunk->trunk == trunk_ref->trunk) {
04405             AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
04406             break;
04407          }
04408       }
04409       AST_LIST_TRAVERSE_SAFE_END
04410       ast_mutex_unlock(&sla.lock);
04411 
04412       if (ringing_trunk) {
04413          answer_trunk_chan(ringing_trunk->trunk->chan);
04414          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04415 
04416          free(ringing_trunk);
04417 
04418          /* Queue up reprocessing ringing trunks, and then ringing stations again */
04419          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04420          sla_queue_event(SLA_EVENT_DIAL_STATE);
04421       }
04422    }
04423 
04424    trunk_ref->chan = chan;
04425 
04426    if (!trunk_ref->trunk->chan) {
04427       ast_mutex_t cond_lock;
04428       ast_cond_t cond;
04429       pthread_t dont_care;
04430       pthread_attr_t attr;
04431       struct dial_trunk_args args = {
04432          .trunk_ref = trunk_ref,
04433          .station = station,
04434          .cond_lock = &cond_lock,
04435          .cond = &cond,
04436       };
04437       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04438       /* Create a thread to dial the trunk and dump it into the conference.
04439        * However, we want to wait until the trunk has been dialed and the
04440        * conference is created before continuing on here. */
04441       ast_autoservice_start(chan);
04442       ast_mutex_init(&cond_lock);
04443       ast_cond_init(&cond, NULL);
04444       pthread_attr_init(&attr);
04445       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04446       ast_mutex_lock(&cond_lock);
04447       ast_pthread_create_background(&dont_care, &attr, dial_trunk, &args);
04448       ast_cond_wait(&cond, &cond_lock);
04449       ast_mutex_unlock(&cond_lock);
04450       ast_mutex_destroy(&cond_lock);
04451       ast_cond_destroy(&cond);
04452       pthread_attr_destroy(&attr);
04453       ast_autoservice_stop(chan);
04454       if (!trunk_ref->trunk->chan) {
04455          ast_log(LOG_DEBUG, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
04456          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
04457          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04458          trunk_ref->chan = NULL;
04459          return 0;
04460       }
04461    }
04462 
04463    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
04464       trunk_ref->trunk->on_hold) {
04465       trunk_ref->trunk->on_hold = 0;
04466       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
04467       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04468    }
04469 
04470    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04471    ast_set_flag(&conf_flags, 
04472       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04473    ast_answer(chan);
04474    conf = build_conf(conf_name, "", "", 0, 0, 1);
04475    if (conf) {
04476       conf_run(chan, conf, conf_flags.flags, NULL);
04477       dispose_conf(conf);
04478       conf = NULL;
04479    }
04480    trunk_ref->chan = NULL;
04481    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04482       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04483       strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
04484       admin_exec(NULL, conf_name);
04485       trunk_ref->trunk->hold_stations = 0;
04486       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04487    }
04488    
04489    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
04490 
04491    return 0;
04492 }

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

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

03522 {
03523    struct sla_ringing_trunk *ringing_trunk;
03524    struct sla_trunk_ref *trunk_ref;
03525    struct sla_station_ref *station_ref;
03526 
03527    ast_dial_join(ringing_station->station->dial);
03528    ast_dial_destroy(ringing_station->station->dial);
03529    ringing_station->station->dial = NULL;
03530 
03531    if (hangup == SLA_STATION_HANGUP_NORMAL)
03532       goto done;
03533 
03534    /* If the station is being hung up because of a timeout, then add it to the
03535     * list of timed out stations on each of the ringing trunks.  This is so
03536     * that when doing further processing to figure out which stations should be
03537     * ringing, which trunk to answer, determining timeouts, etc., we know which
03538     * ringing trunks we should ignore. */
03539    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03540       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03541          if (ringing_trunk->trunk == trunk_ref->trunk)
03542             break;
03543       }
03544       if (!trunk_ref)
03545          continue;
03546       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
03547          continue;
03548       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
03549    }
03550 
03551 done:
03552    free(ringing_station);
03553 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

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

03506 {
03507    char buf[80];
03508    struct sla_station_ref *station_ref;
03509 
03510    snprintf(buf, sizeof(buf), "SLA_%s|K", ringing_trunk->trunk->name);
03511    admin_exec(NULL, buf);
03512    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03513 
03514    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
03515       free(station_ref);
03516 
03517    free(ringing_trunk);
03518 }

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

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

04154 {
04155    struct sla_failed_station *failed_station;
04156    struct sla_ringing_station *ringing_station;
04157 
04158    ast_mutex_lock(&sla.lock);
04159 
04160    while (!sla.stop) {
04161       struct sla_event *event;
04162       struct timespec ts = { 0, };
04163       unsigned int have_timeout = 0;
04164 
04165       if (AST_LIST_EMPTY(&sla.event_q)) {
04166          if ((have_timeout = sla_process_timers(&ts)))
04167             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
04168          else
04169             ast_cond_wait(&sla.cond, &sla.lock);
04170          if (sla.stop)
04171             break;
04172       }
04173 
04174       if (have_timeout)
04175          sla_process_timers(NULL);
04176 
04177       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
04178          ast_mutex_unlock(&sla.lock);
04179          switch (event->type) {
04180          case SLA_EVENT_HOLD:
04181             sla_handle_hold_event(event);
04182             break;
04183          case SLA_EVENT_DIAL_STATE:
04184             sla_handle_dial_state_event();
04185             break;
04186          case SLA_EVENT_RINGING_TRUNK:
04187             sla_handle_ringing_trunk_event();
04188             break;
04189          }
04190          free(event);
04191          ast_mutex_lock(&sla.lock);
04192       }
04193    }
04194 
04195    ast_mutex_unlock(&sla.lock);
04196 
04197    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
04198       free(ringing_station);
04199 
04200    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
04201       free(failed_station);
04202 
04203    return NULL;
04204 }

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

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

04528 {
04529    const char *trunk_name = data;
04530    char conf_name[MAX_CONFNUM];
04531    struct ast_conference *conf;
04532    struct ast_flags conf_flags = { 0 };
04533    struct sla_trunk *trunk;
04534    struct sla_ringing_trunk *ringing_trunk;
04535 
04536    AST_RWLIST_RDLOCK(&sla_trunks);
04537    trunk = sla_find_trunk(trunk_name);
04538    AST_RWLIST_UNLOCK(&sla_trunks);
04539    if (!trunk) {
04540       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", trunk_name);
04541       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04542       return 0;
04543    }
04544    if (trunk->chan) {
04545       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
04546          trunk_name);
04547       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04548       return 0;
04549    }
04550    trunk->chan = chan;
04551 
04552    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
04553       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04554       return 0;
04555    }
04556 
04557    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_name);
04558    conf = build_conf(conf_name, "", "", 1, 1, 1);
04559    if (!conf) {
04560       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04561       return 0;
04562    }
04563    ast_set_flag(&conf_flags, 
04564       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
04565    ast_indicate(chan, AST_CONTROL_RINGING);
04566    conf_run(chan, conf, conf_flags.flags, NULL);
04567    dispose_conf(conf);
04568    conf = NULL;
04569    trunk->chan = NULL;
04570    trunk->on_hold = 0;
04571 
04572    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04573 
04574    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
04575       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
04576 
04577    /* Remove the entry from the list of ringing trunks if it is still there. */
04578    ast_mutex_lock(&sla.lock);
04579    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04580       if (ringing_trunk->trunk == trunk) {
04581          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
04582          break;
04583       }
04584    }
04585    AST_LIST_TRAVERSE_SAFE_END
04586    ast_mutex_unlock(&sla.lock);
04587    if (ringing_trunk) {
04588       free(ringing_trunk);
04589       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
04590       /* Queue reprocessing of ringing trunks to make stations stop ringing
04591        * that shouldn't be ringing after this trunk stopped. */
04592       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04593    }
04594 
04595    return 0;
04596 }

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

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

01133 {
01134 #define S(e) case e: return # e;
01135    switch (state) {
01136    S(SLA_TRUNK_STATE_IDLE)
01137    S(SLA_TRUNK_STATE_RINGING)
01138    S(SLA_TRUNK_STATE_UP)
01139    S(SLA_TRUNK_STATE_ONHOLD)
01140    S(SLA_TRUNK_STATE_ONHOLD_BYME)
01141    }
01142    return "Uknown State";
01143 #undef S
01144 }

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(), and conf_run().

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(), and conf_run().

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

05029 {
05030    int res = 0;
05031    
05032    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05033    res = ast_manager_unregister("MeetmeMute");
05034    res |= ast_manager_unregister("MeetmeUnmute");
05035    res |= ast_unregister_application(app3);
05036    res |= ast_unregister_application(app2);
05037    res |= ast_unregister_application(app);
05038    res |= ast_unregister_application(slastation_app);
05039    res |= ast_unregister_application(slatrunk_app);
05040 
05041    ast_devstate_prov_del("Meetme");
05042    ast_devstate_prov_del("SLA");
05043 
05044    ast_module_user_hangup_all();
05045    
05046    sla_destroy();
05047 
05048    return res;
05049 }


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 5085 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 5085 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 1219 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 1069 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 1215 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 1146 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 Thu Mar 25 12:09:41 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7