Thu Oct 1 13:09:12 2009

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 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 int set_listen_volume (struct ast_conf_user *user, int volume)
static int set_talk_volume (struct ast_conf_user *user, int volume)
static void sla_add_trunk_to_station (struct sla_station *station, struct ast_variable *var)
static int sla_build_station (struct ast_config *cfg, const char *cat)
static int sla_build_trunk (struct ast_config *cfg, const char *cat)
static int sla_calc_station_delays (unsigned int *timeout)
 Calculate the ring delay for a station.
static int sla_calc_station_timeouts (unsigned int *timeout)
 Process station ring timeouts.
static int sla_calc_trunk_timeouts (unsigned int *timeout)
 Process trunk ring timeouts.
static void sla_change_trunk_state (const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
static int sla_check_device (const char *device)
static int sla_check_failed_station (const struct sla_station *station)
 Check to see if this station has failed to be dialed in the past minute.
static int sla_check_inuse_station (const struct sla_station *station)
 Check to see if a station is in use.
static 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 = "6989f2ec67f8497e38c12890500c525b" , .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 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 328 of file app_meetme.c.

00328                    {
00329    CONF_HASJOIN,
00330    CONF_HASLEFT
00331 };

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

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

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

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

enum sla_station_hangup

Enumerator:
SLA_STATION_HANGUP_NORMAL 
SLA_STATION_HANGUP_TIMEOUT 

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

enum sla_which_trunk_refs

Enumerator:
ALL_TRUNK_REFS 
INACTIVE_TRUNK_REFS 

Definition at line 403 of file app_meetme.c.

00403                           {
00404    ALL_TRUNK_REFS,
00405    INACTIVE_TRUNK_REFS,
00406 };

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

static void __unreg_module ( void   )  [static]

Definition at line 5046 of file app_meetme.c.

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

Definition at line 3159 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03160 {
03161    return meetmemute(s, m, 1);
03162 }

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

Definition at line 3164 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03165 {
03166    return meetmemute(s, m, 0);
03167 }

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

The MeetMeadmin application.

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

02945                                                             {
02946    char *params;
02947    struct ast_conference *cnf;
02948    struct ast_conf_user *user = NULL;
02949    struct ast_module_user *u;
02950    AST_DECLARE_APP_ARGS(args,
02951       AST_APP_ARG(confno);
02952       AST_APP_ARG(command);
02953       AST_APP_ARG(user);
02954    );
02955 
02956    if (ast_strlen_zero(data)) {
02957       ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
02958       return -1;
02959    }
02960 
02961    u = ast_module_user_add(chan);
02962 
02963    AST_LIST_LOCK(&confs);
02964    
02965    params = ast_strdupa(data);
02966    AST_STANDARD_APP_ARGS(args, params);
02967 
02968    if (!args.command) {
02969       ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
02970       AST_LIST_UNLOCK(&confs);
02971       ast_module_user_remove(u);
02972       return -1;
02973    }
02974    AST_LIST_TRAVERSE(&confs, cnf, list) {
02975       if (!strcmp(cnf->confno, args.confno))
02976          break;
02977    }
02978 
02979    if (!cnf) {
02980       ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
02981       AST_LIST_UNLOCK(&confs);
02982       ast_module_user_remove(u);
02983       return 0;
02984    }
02985 
02986    ast_atomic_fetchadd_int(&cnf->refcount, 1);
02987 
02988    if (args.user)
02989       user = find_user(cnf, args.user);
02990 
02991    switch (*args.command) {
02992    case 76: /* L: Lock */ 
02993       cnf->locked = 1;
02994       break;
02995    case 108: /* l: Unlock */ 
02996       cnf->locked = 0;
02997       break;
02998    case 75: /* K: kick all users */
02999       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03000          user->adminflags |= ADMINFLAG_KICKME;
03001       break;
03002    case 101: /* e: Eject last user*/
03003       user = AST_LIST_LAST(&cnf->userlist);
03004       if (!(user->userflags & CONFFLAG_ADMIN))
03005          user->adminflags |= ADMINFLAG_KICKME;
03006       else
03007          ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
03008       break;
03009    case 77: /* M: Mute */ 
03010       if (user) {
03011          user->adminflags |= ADMINFLAG_MUTED;
03012       } else
03013          ast_log(LOG_NOTICE, "Specified User not found!\n");
03014       break;
03015    case 78: /* N: Mute all (non-admin) users */
03016       AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03017          if (!(user->userflags & CONFFLAG_ADMIN))
03018             user->adminflags |= ADMINFLAG_MUTED;
03019       }
03020       break;               
03021    case 109: /* m: Unmute */ 
03022       if (user) {
03023          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
03024       } else
03025          ast_log(LOG_NOTICE, "Specified User not found!\n");
03026       break;
03027    case 110: /* n: Unmute all users */
03028       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03029          user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
03030       break;
03031    case 107: /* k: Kick user */ 
03032       if (user)
03033          user->adminflags |= ADMINFLAG_KICKME;
03034       else
03035          ast_log(LOG_NOTICE, "Specified User not found!\n");
03036       break;
03037    case 118: /* v: Lower all users listen volume */
03038       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03039          tweak_listen_volume(user, VOL_DOWN);
03040       break;
03041    case 86: /* V: Raise all users listen volume */
03042       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03043          tweak_listen_volume(user, VOL_UP);
03044       break;
03045    case 115: /* s: Lower all users speaking volume */
03046       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03047          tweak_talk_volume(user, VOL_DOWN);
03048       break;
03049    case 83: /* S: Raise all users speaking volume */
03050       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03051          tweak_talk_volume(user, VOL_UP);
03052       break;
03053    case 82: /* R: Reset all volume levels */
03054       AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03055          reset_volumes(user);
03056       break;
03057    case 114: /* r: Reset user's volume level */
03058       if (user)
03059          reset_volumes(user);
03060       else
03061          ast_log(LOG_NOTICE, "Specified User not found!\n");
03062       break;
03063    case 85: /* U: Raise user's listen volume */
03064       if (user)
03065          tweak_listen_volume(user, VOL_UP);
03066       else
03067          ast_log(LOG_NOTICE, "Specified User not found!\n");
03068       break;
03069    case 117: /* u: Lower user's listen volume */
03070       if (user)
03071          tweak_listen_volume(user, VOL_DOWN);
03072       else
03073          ast_log(LOG_NOTICE, "Specified User not found!\n");
03074       break;
03075    case 84: /* T: Raise user's talk volume */
03076       if (user)
03077          tweak_talk_volume(user, VOL_UP);
03078       else
03079          ast_log(LOG_NOTICE, "Specified User not found!\n");
03080       break;
03081    case 116: /* t: Lower user's talk volume */
03082       if (user) 
03083          tweak_talk_volume(user, VOL_DOWN);
03084       else 
03085          ast_log(LOG_NOTICE, "Specified User not found!\n");
03086       break;
03087    }
03088 
03089    AST_LIST_UNLOCK(&confs);
03090 
03091    dispose_conf(cnf);
03092 
03093    ast_module_user_remove(u);
03094    
03095    return 0;
03096 }

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

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

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

static void answer_trunk_chan ( struct ast_channel chan  )  [static]

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

03416 {
03417    ast_answer(chan);
03418    ast_indicate(chan, -1);
03419 }

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

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

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

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

01490 {
01491    if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01492       return 1;
01493    }
01494 
01495    return (chan->_state == AST_STATE_UP);
01496 }

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

Definition at line 606 of file app_meetme.c.

References ast_log(), errno, and LOG_WARNING.

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

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

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

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

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

The meetme() application.

Definition at line 2682 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, meetme_opts, OPT_ARG_ARRAY_SIZE, ast_conference::pin, ast_conference::pinadmin, and var.

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

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

Definition at line 1230 of file app_meetme.c.

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

Referenced by conf_run().

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

static int conf_free ( struct ast_conference conf  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

The MeetmeCount application.

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

02632 {
02633    struct ast_module_user *u;
02634    int res = 0;
02635    struct ast_conference *conf;
02636    int count;
02637    char *localdata;
02638    char val[80] = "0"; 
02639    AST_DECLARE_APP_ARGS(args,
02640       AST_APP_ARG(confno);
02641       AST_APP_ARG(varname);
02642    );
02643 
02644    if (ast_strlen_zero(data)) {
02645       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
02646       return -1;
02647    }
02648 
02649    u = ast_module_user_add(chan);
02650    
02651    if (!(localdata = ast_strdupa(data))) {
02652       ast_module_user_remove(u);
02653       return -1;
02654    }
02655 
02656    AST_STANDARD_APP_ARGS(args, localdata);
02657    
02658    conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
02659 
02660    if (conf) {
02661       count = conf->users;
02662       dispose_conf(conf);
02663       conf = NULL;
02664    } else
02665       count = 0;
02666 
02667    if (!ast_strlen_zero(args.varname)){
02668       /* have var so load it and exit */
02669       snprintf(val, sizeof(val), "%d",count);
02670       pbx_builtin_setvar_helper(chan, args.varname, val);
02671    } else {
02672       if (chan->_state != AST_STATE_UP)
02673          ast_answer(chan);
02674       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
02675    }
02676    ast_module_user_remove(u);
02677 
02678    return res;
02679 }

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

Definition at line 4455 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

04456 {
04457    struct sla_trunk_ref *trunk_ref;
04458 
04459    if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
04460       return NULL;
04461 
04462    trunk_ref->trunk = trunk;
04463 
04464    return trunk_ref;
04465 }

static void destroy_station ( struct sla_station station  )  [static]

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

04624 {
04625    struct sla_trunk_ref *trunk_ref;
04626 
04627    if (!ast_strlen_zero(station->autocontext)) {
04628       AST_RWLIST_RDLOCK(&sla_trunks);
04629       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04630          char exten[AST_MAX_EXTENSION];
04631          char hint[AST_MAX_APP];
04632          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04633          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04634          ast_context_remove_extension(station->autocontext, exten, 
04635             1, sla_registrar);
04636          ast_context_remove_extension(station->autocontext, hint, 
04637             PRIORITY_HINT, sla_registrar);
04638       }
04639       AST_RWLIST_UNLOCK(&sla_trunks);
04640    }
04641 
04642    while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
04643       free(trunk_ref);
04644 
04645    ast_string_field_free_memory(station);
04646    free(station);
04647 }

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

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

04610 {
04611    struct sla_station_ref *station_ref;
04612 
04613    if (!ast_strlen_zero(trunk->autocontext))
04614       ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
04615 
04616    while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
04617       free(station_ref);
04618 
04619    ast_string_field_free_memory(trunk);
04620    free(trunk);
04621 }

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

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

04175 {
04176    struct dial_trunk_args *args = data;
04177    struct ast_dial *dial;
04178    char *tech, *tech_data;
04179    enum ast_dial_result dial_res;
04180    char conf_name[MAX_CONFNUM];
04181    struct ast_conference *conf;
04182    struct ast_flags conf_flags = { 0 };
04183    struct sla_trunk_ref *trunk_ref = args->trunk_ref;
04184    const char *cid_name = NULL, *cid_num = NULL;
04185 
04186    if (!(dial = ast_dial_create())) {
04187       ast_mutex_lock(args->cond_lock);
04188       ast_cond_signal(args->cond);
04189       ast_mutex_unlock(args->cond_lock);
04190       return NULL;
04191    }
04192 
04193    tech_data = ast_strdupa(trunk_ref->trunk->device);
04194    tech = strsep(&tech_data, "/");
04195    if (ast_dial_append(dial, tech, tech_data) == -1) {
04196       ast_mutex_lock(args->cond_lock);
04197       ast_cond_signal(args->cond);
04198       ast_mutex_unlock(args->cond_lock);
04199       ast_dial_destroy(dial);
04200       return NULL;
04201    }
04202 
04203    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
04204       cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
04205       free(trunk_ref->chan->cid.cid_name);
04206       trunk_ref->chan->cid.cid_name = NULL;
04207    }
04208    if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
04209       cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
04210       free(trunk_ref->chan->cid.cid_num);
04211       trunk_ref->chan->cid.cid_num = NULL;
04212    }
04213 
04214    dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
04215 
04216    if (cid_name)
04217       trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
04218    if (cid_num)
04219       trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
04220 
04221    if (dial_res != AST_DIAL_RESULT_TRYING) {
04222       ast_mutex_lock(args->cond_lock);
04223       ast_cond_signal(args->cond);
04224       ast_mutex_unlock(args->cond_lock);
04225       ast_dial_destroy(dial);
04226       return NULL;
04227    }
04228 
04229    for (;;) {
04230       unsigned int done = 0;
04231       switch ((dial_res = ast_dial_state(dial))) {
04232       case AST_DIAL_RESULT_ANSWERED:
04233          trunk_ref->trunk->chan = ast_dial_answered(dial);
04234       case AST_DIAL_RESULT_HANGUP:
04235       case AST_DIAL_RESULT_INVALID:
04236       case AST_DIAL_RESULT_FAILED:
04237       case AST_DIAL_RESULT_TIMEOUT:
04238       case AST_DIAL_RESULT_UNANSWERED:
04239          done = 1;
04240       case AST_DIAL_RESULT_TRYING:
04241       case AST_DIAL_RESULT_RINGING:
04242       case AST_DIAL_RESULT_PROGRESS:
04243       case AST_DIAL_RESULT_PROCEEDING:
04244          break;
04245       }
04246       if (done)
04247          break;
04248    }
04249 
04250    if (!trunk_ref->trunk->chan) {
04251       ast_mutex_lock(args->cond_lock);
04252       ast_cond_signal(args->cond);
04253       ast_mutex_unlock(args->cond_lock);
04254       ast_dial_join(dial);
04255       ast_dial_destroy(dial);
04256       return NULL;
04257    }
04258 
04259    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04260    ast_set_flag(&conf_flags, 
04261       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | 
04262       CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
04263    conf = build_conf(conf_name, "", "", 1, 1, 1);
04264 
04265    ast_mutex_lock(args->cond_lock);
04266    ast_cond_signal(args->cond);
04267    ast_mutex_unlock(args->cond_lock);
04268 
04269    if (conf) {
04270       conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
04271       dispose_conf(conf);
04272       conf = NULL;
04273    }
04274 
04275    /* If the trunk is going away, it is definitely now IDLE. */
04276    sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04277 
04278    trunk_ref->trunk->chan = NULL;
04279    trunk_ref->trunk->on_hold = 0;
04280 
04281    ast_dial_join(dial);
04282    ast_dial_destroy(dial);
04283 
04284    return NULL;
04285 }

static int dispose_conf ( struct ast_conference conf  )  [static]

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

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

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

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

Referenced by conf_exec(), and count_exec().

02539 {
02540    struct ast_config *cfg;
02541    struct ast_variable *var;
02542    struct ast_conference *cnf;
02543    char *parse;
02544    AST_DECLARE_APP_ARGS(args,
02545       AST_APP_ARG(confno);
02546       AST_APP_ARG(pin);
02547       AST_APP_ARG(pinadmin);
02548    );
02549 
02550    /* Check first in the conference list */
02551    AST_LIST_LOCK(&confs);
02552    AST_LIST_TRAVERSE(&confs, cnf, list) {
02553       if (!strcmp(confno, cnf->confno)) 
02554          break;
02555    }
02556    if (cnf){
02557       cnf->refcount += refcount;
02558    }
02559    AST_LIST_UNLOCK(&confs);
02560 
02561    if (!cnf) {
02562       if (dynamic) {
02563          /* No need to parse meetme.conf */
02564          ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
02565          if (dynamic_pin) {
02566             if (dynamic_pin[0] == 'q') {
02567                /* Query the user to enter a PIN */
02568                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
02569                   return NULL;
02570             }
02571             cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount);
02572          } else {
02573             cnf = build_conf(confno, "", "", make, dynamic, refcount);
02574          }
02575       } else {
02576          /* Check the config */
02577          cfg = ast_config_load(CONFIG_FILE_NAME);
02578          if (!cfg) {
02579             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
02580             return NULL;
02581          }
02582          for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
02583             if (strcasecmp(var->name, "conf"))
02584                continue;
02585             
02586             if (!(parse = ast_strdupa(var->value)))
02587                return NULL;
02588             
02589             AST_NONSTANDARD_APP_ARGS(args, parse, ',');
02590             if (!strcasecmp(args.confno, confno)) {
02591                /* Bingo it's a valid conference */
02592                cnf = build_conf(args.confno,
02593                      S_OR(args.pin, ""),
02594                      S_OR(args.pinadmin, ""),
02595                      make, dynamic, refcount);
02596                break;
02597             }
02598          }
02599          if (!var) {
02600             ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
02601          }
02602          ast_config_destroy(cfg);
02603       }
02604    } else if (dynamic_pin) {
02605       /* Correct for the user selecting 'D' instead of 'd' to have
02606          someone join into a conference that has already been created
02607          with a pin. */
02608       if (dynamic_pin[0] == 'q')
02609          dynamic_pin[0] = '\0';
02610    }
02611 
02612    if (cnf) {
02613       if (confflags && !cnf->chan &&
02614           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
02615           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
02616          ast_log(LOG_WARNING, "No %s channel available for conference, user introduction disabled\n", dahdi_chan_name);
02617          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
02618       }
02619       
02620       if (confflags && !cnf->chan &&
02621           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
02622          ast_log(LOG_WARNING, "No %s channel available for conference, conference recording disabled\n", dahdi_chan_name);
02623          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
02624       }
02625    }
02626 
02627    return cnf;
02628 }

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

02481 {
02482    struct ast_variable *var, *save;
02483    struct ast_conference *cnf;
02484 
02485    /* Check first in the conference list */
02486    AST_LIST_LOCK(&confs);
02487    AST_LIST_TRAVERSE(&confs, cnf, list) {
02488       if (!strcmp(confno, cnf->confno)) 
02489          break;
02490    }
02491    if (cnf) {
02492       cnf->refcount += refcount;
02493    }
02494    AST_LIST_UNLOCK(&confs);
02495 
02496    if (!cnf) {
02497       char *pin = NULL, *pinadmin = NULL; /* For temp use */
02498       
02499       var = ast_load_realtime("meetme", "confno", confno, NULL);
02500 
02501       if (!var)
02502          return NULL;
02503 
02504       save = var;
02505       while (var) {
02506          if (!strcasecmp(var->name, "pin")) {
02507             pin = ast_strdupa(var->value);
02508          } else if (!strcasecmp(var->name, "adminpin")) {
02509             pinadmin = ast_strdupa(var->value);
02510          }
02511          var = var->next;
02512       }
02513       ast_variables_destroy(save);
02514       
02515       cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount);
02516    }
02517 
02518    if (cnf) {
02519       if (confflags && !cnf->chan &&
02520           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
02521           ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
02522          ast_log(LOG_WARNING, "No %s channel available for conference, user introduction disabled\n", dahdi_chan_name);
02523          ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
02524       }
02525       
02526       if (confflags && !cnf->chan &&
02527           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
02528          ast_log(LOG_WARNING, "No %s channel available for conference, conference recording disabled\n", dahdi_chan_name);
02529          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
02530       }
02531    }
02532 
02533    return cnf;
02534 }

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

Definition at line 2928 of file app_meetme.c.

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

02929 {
02930    struct ast_conf_user *user = NULL;
02931    int cid;
02932    
02933    sscanf(callerident, "%30i", &cid);
02934    if (conf && callerident) {
02935       AST_LIST_TRAVERSE(&conf->userlist, user, list) {
02936          if (cid == user->user_no)
02937             return user;
02938       }
02939    }
02940    return NULL;
02941 }

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

Definition at line 1422 of file app_meetme.c.

References CONF_HASJOIN.

Referenced by announce_thread().

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

static char* istalking ( int  x  )  [static]

Definition at line 596 of file app_meetme.c.

Referenced by meetme_cmd().

00597 {
00598    if (x > 0)
00599       return "(talking)";
00600    else if (x < 0)
00601       return "(unmonitored)";
00602    else 
00603       return "(not talking)";
00604 }

static int load_config ( int  reload  )  [static]

Definition at line 4978 of file app_meetme.c.

References load_config_meetme(), and sla_load_config().

04979 {
04980    int res = 0;
04981 
04982    load_config_meetme();
04983    if (!reload)
04984       res = sla_load_config();
04985 
04986    return res;
04987 }

static void load_config_meetme ( void   )  [static]

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

03257 {
03258    struct ast_config *cfg;
03259    const char *val;
03260 
03261    audio_buffers = DEFAULT_AUDIO_BUFFERS;
03262 
03263    if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
03264       return;
03265 
03266    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03267       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
03268          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03269          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03270       } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
03271          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03272             DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
03273          audio_buffers = DEFAULT_AUDIO_BUFFERS;
03274       }
03275       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03276          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03277    }
03278 
03279    ast_config_destroy(cfg);
03280 }

static int load_module ( void   )  [static]

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

05013 {
05014    int res = 0;
05015 
05016    res |= load_config(0);
05017 
05018    ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05019    res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL, 
05020                 action_meetmemute, "Mute a Meetme user");
05021    res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL, 
05022                 action_meetmeunmute, "Unmute a Meetme user");
05023    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
05024    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
05025    res |= ast_register_application(app, conf_exec, synopsis, descrip);
05026    res |= ast_register_application(slastation_app, sla_station_exec,
05027                slastation_synopsis, slastation_desc);
05028    res |= ast_register_application(slatrunk_app, sla_trunk_exec,
05029                slatrunk_synopsis, slatrunk_desc);
05030 
05031    res |= ast_devstate_prov_add("Meetme", meetmestate);
05032    res |= ast_devstate_prov_add("SLA", sla_state);
05033 
05034    return res;
05035 }

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

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

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

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

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

03099 {
03100    struct ast_conference *conf;
03101    struct ast_conf_user *user;
03102    const char *confid = astman_get_header(m, "Meetme");
03103    char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
03104    int userno;
03105 
03106    if (ast_strlen_zero(confid)) {
03107       astman_send_error(s, m, "Meetme conference not specified");
03108       return 0;
03109    }
03110 
03111    if (ast_strlen_zero(userid)) {
03112       astman_send_error(s, m, "Meetme user number not specified");
03113       return 0;
03114    }
03115 
03116    userno = strtoul(userid, &userid, 10);
03117 
03118    if (*userid) {
03119       astman_send_error(s, m, "Invalid user number");
03120       return 0;
03121    }
03122 
03123    /* Look in the conference list */
03124    AST_LIST_LOCK(&confs);
03125    AST_LIST_TRAVERSE(&confs, conf, list) {
03126       if (!strcmp(confid, conf->confno))
03127          break;
03128    }
03129 
03130    if (!conf) {
03131       AST_LIST_UNLOCK(&confs);
03132       astman_send_error(s, m, "Meetme conference does not exist");
03133       return 0;
03134    }
03135 
03136    AST_LIST_TRAVERSE(&conf->userlist, user, list)
03137       if (user->user_no == userno)
03138          break;
03139 
03140    if (!user) {
03141       AST_LIST_UNLOCK(&confs);
03142       astman_send_error(s, m, "User number not found");
03143       return 0;
03144    }
03145 
03146    if (mute)
03147       user->adminflags |= ADMINFLAG_MUTED;   /* request user muting */
03148    else
03149       user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);  /* request user unmuting */
03150 
03151    AST_LIST_UNLOCK(&confs);
03152 
03153    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);
03154 
03155    astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
03156    return 0;
03157 }

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

Callback for devicestate providers.

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

03235 {
03236    struct ast_conference *conf;
03237 
03238    /* Find conference */
03239    AST_LIST_LOCK(&confs);
03240    AST_LIST_TRAVERSE(&confs, conf, list) {
03241       if (!strcmp(data, conf->confno))
03242          break;
03243    }
03244    AST_LIST_UNLOCK(&confs);
03245    if (!conf)
03246       return AST_DEVICE_INVALID;
03247 
03248 
03249    /* SKREP to fill */
03250    if (!conf->users)
03251       return AST_DEVICE_NOT_INUSE;
03252 
03253    return AST_DEVICE_INUSE;
03254 }

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

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

04468 {
04469    struct sla_ringing_trunk *ringing_trunk;
04470 
04471    if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
04472       return NULL;
04473    
04474    ringing_trunk->trunk = trunk;
04475    ringing_trunk->ring_begin = ast_tvnow();
04476 
04477    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
04478 
04479    ast_mutex_lock(&sla.lock);
04480    AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
04481    ast_mutex_unlock(&sla.lock);
04482 
04483    sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04484 
04485    return ringing_trunk;
04486 }

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

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

03170 {
03171    struct ast_conference *cnf = args;
03172    struct ast_frame *f=NULL;
03173    int flags;
03174    struct ast_filestream *s=NULL;
03175    int res=0;
03176    int x;
03177    const char *oldrecordingfilename = NULL;
03178 
03179    if (!cnf || !cnf->lchan) {
03180       pthread_exit(0);
03181    }
03182 
03183    ast_stopstream(cnf->lchan);
03184    flags = O_CREAT|O_TRUNC|O_WRONLY;
03185 
03186 
03187    cnf->recording = MEETME_RECORD_ACTIVE;
03188    while (ast_waitfor(cnf->lchan, -1) > -1) {
03189       if (cnf->recording == MEETME_RECORD_TERMINATE) {
03190          AST_LIST_LOCK(&confs);
03191          AST_LIST_UNLOCK(&confs);
03192          break;
03193       }
03194       if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
03195          s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
03196          oldrecordingfilename = cnf->recordingfilename;
03197       }
03198       
03199       f = ast_read(cnf->lchan);
03200       if (!f) {
03201          res = -1;
03202          break;
03203       }
03204       if (f->frametype == AST_FRAME_VOICE) {
03205          ast_mutex_lock(&cnf->listenlock);
03206          for (x=0;x<AST_FRAME_BITS;x++) {
03207             /* Free any translations that have occured */
03208             if (cnf->transframe[x]) {
03209                ast_frfree(cnf->transframe[x]);
03210                cnf->transframe[x] = NULL;
03211             }
03212          }
03213          if (cnf->origframe)
03214             ast_frfree(cnf->origframe);
03215          cnf->origframe = ast_frdup(f);
03216          ast_mutex_unlock(&cnf->listenlock);
03217          if (s)
03218             res = ast_writestream(s, f);
03219          if (res) {
03220             ast_frfree(f);
03221             break;
03222          }
03223       }
03224       ast_frfree(f);
03225    }
03226    cnf->recording = MEETME_RECORD_OFF;
03227    if (s)
03228       ast_closestream(s);
03229    
03230    pthread_exit(0);
03231 }

static int reload ( void   )  [static]

Definition at line 5037 of file app_meetme.c.

References load_config().

05038 {
05039    return load_config(1);
05040 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 716 of file app_meetme.c.

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

Referenced by admin_exec().

00717 {
00718    signed char zero_volume = 0;
00719 
00720    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00721    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00722 }

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

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

03422 {
03423    struct sla_station *station;
03424    struct sla_trunk_ref *trunk_ref;
03425    char conf_name[MAX_CONFNUM];
03426    struct ast_flags conf_flags = { 0 };
03427    struct ast_conference *conf;
03428 
03429    {
03430       struct run_station_args *args = data;
03431       station = args->station;
03432       trunk_ref = args->trunk_ref;
03433       ast_mutex_lock(args->cond_lock);
03434       ast_cond_signal(args->cond);
03435       ast_mutex_unlock(args->cond_lock);
03436       /* args is no longer valid here. */
03437    }
03438 
03439    ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
03440    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
03441    ast_set_flag(&conf_flags, 
03442       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
03443    answer_trunk_chan(trunk_ref->chan);
03444    conf = build_conf(conf_name, "", "", 0, 0, 1);
03445    if (conf) {
03446       conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
03447       dispose_conf(conf);
03448       conf = NULL;
03449    }
03450    trunk_ref->chan = NULL;
03451    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
03452       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
03453       strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
03454       admin_exec(NULL, conf_name);
03455       trunk_ref->trunk->hold_stations = 0;
03456       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03457    }
03458 
03459    ast_dial_join(station->dial);
03460    ast_dial_destroy(station->dial);
03461    station->dial = NULL;
03462 
03463    return NULL;
03464 }

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

Definition at line 645 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

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

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

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

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

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

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

04771 {
04772    struct sla_trunk *trunk;
04773    struct sla_trunk_ref *trunk_ref;
04774    struct sla_station_ref *station_ref;
04775    char *trunk_name, *options, *cur;
04776 
04777    options = ast_strdupa(var->value);
04778    trunk_name = strsep(&options, ",");
04779    
04780    AST_RWLIST_RDLOCK(&sla_trunks);
04781    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04782       if (!strcasecmp(trunk->name, trunk_name))
04783          break;
04784    }
04785 
04786    AST_RWLIST_UNLOCK(&sla_trunks);
04787    if (!trunk) {
04788       ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
04789       return;
04790    }
04791    if (!(trunk_ref = create_trunk_ref(trunk)))
04792       return;
04793    trunk_ref->state = SLA_TRUNK_STATE_IDLE;
04794 
04795    while ((cur = strsep(&options, ","))) {
04796       char *name, *value = cur;
04797       name = strsep(&value, "=");
04798       if (!strcasecmp(name, "ringtimeout")) {
04799          if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
04800             ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
04801                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04802             trunk_ref->ring_timeout = 0;
04803          }
04804       } else if (!strcasecmp(name, "ringdelay")) {
04805          if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
04806             ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
04807                "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
04808             trunk_ref->ring_delay = 0;
04809          }
04810       } else {
04811          ast_log(LOG_WARNING, "Invalid option '%s' for "
04812             "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
04813       }
04814    }
04815 
04816    if (!(station_ref = sla_create_station_ref(station))) {
04817       free(trunk_ref);
04818       return;
04819    }
04820    ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
04821    AST_RWLIST_WRLOCK(&sla_trunks);
04822    AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
04823    AST_RWLIST_UNLOCK(&sla_trunks);
04824    AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
04825 }

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

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

04828 {
04829    struct sla_station *station;
04830    struct ast_variable *var;
04831    const char *dev;
04832 
04833    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
04834       ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
04835       return -1;
04836    }
04837 
04838    if (!(station = ast_calloc(1, sizeof(*station))))
04839       return -1;
04840    if (ast_string_field_init(station, 32)) {
04841       free(station);
04842       return -1;
04843    }
04844 
04845    ast_string_field_set(station, name, cat);
04846    ast_string_field_set(station, device, dev);
04847 
04848    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04849       if (!strcasecmp(var->name, "trunk"))
04850          sla_add_trunk_to_station(station, var);
04851       else if (!strcasecmp(var->name, "autocontext"))
04852          ast_string_field_set(station, autocontext, var->value);
04853       else if (!strcasecmp(var->name, "ringtimeout")) {
04854          if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
04855             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
04856                var->value, station->name);
04857             station->ring_timeout = 0;
04858          }
04859       } else if (!strcasecmp(var->name, "ringdelay")) {
04860          if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
04861             ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
04862                var->value, station->name);
04863             station->ring_delay = 0;
04864          }
04865       } else if (!strcasecmp(var->name, "hold")) {
04866          if (!strcasecmp(var->value, "private"))
04867             station->hold_access = SLA_HOLD_PRIVATE;
04868          else if (!strcasecmp(var->value, "open"))
04869             station->hold_access = SLA_HOLD_OPEN;
04870          else {
04871             ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
04872                var->value, station->name);
04873          }
04874 
04875       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
04876          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
04877             var->name, var->lineno, SLA_CONFIG_FILE);
04878       }
04879    }
04880 
04881    if (!ast_strlen_zero(station->autocontext)) {
04882       struct ast_context *context;
04883       struct sla_trunk_ref *trunk_ref;
04884       context = ast_context_find_or_create(NULL, station->autocontext, sla_registrar);
04885       if (!context) {
04886          ast_log(LOG_ERROR, "Failed to automatically find or create "
04887             "context '%s' for SLA!\n", station->autocontext);
04888          destroy_station(station);
04889          return -1;
04890       }
04891       /* The extension for when the handset goes off-hook.
04892        * exten => station1,1,SLAStation(station1) */
04893       if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
04894          NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
04895          ast_log(LOG_ERROR, "Failed to automatically create extension "
04896             "for trunk '%s'!\n", station->name);
04897          destroy_station(station);
04898          return -1;
04899       }
04900       AST_RWLIST_RDLOCK(&sla_trunks);
04901       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04902          char exten[AST_MAX_EXTENSION];
04903          char hint[AST_MAX_APP];
04904          snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
04905          snprintf(hint, sizeof(hint), "SLA:%s", exten);
04906          /* Extension for this line button 
04907           * exten => station1_line1,1,SLAStation(station1_line1) */
04908          if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
04909             NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
04910             ast_log(LOG_ERROR, "Failed to automatically create extension "
04911                "for trunk '%s'!\n", station->name);
04912             destroy_station(station);
04913             return -1;
04914          }
04915          /* Hint for this line button 
04916           * exten => station1_line1,hint,SLA:station1_line1 */
04917          if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
04918             NULL, NULL, hint, NULL, NULL, sla_registrar)) {
04919             ast_log(LOG_ERROR, "Failed to automatically create hint "
04920                "for trunk '%s'!\n", station->name);
04921             destroy_station(station);
04922             return -1;
04923          }
04924       }
04925       AST_RWLIST_UNLOCK(&sla_trunks);
04926    }
04927 
04928    AST_RWLIST_WRLOCK(&sla_stations);
04929    AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
04930    AST_RWLIST_UNLOCK(&sla_stations);
04931 
04932    return 0;
04933 }

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

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

04693 {
04694    struct sla_trunk *trunk;
04695    struct ast_variable *var;
04696    const char *dev;
04697 
04698    if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
04699       ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
04700       return -1;
04701    }
04702 
04703    if (sla_check_device(dev)) {
04704       ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
04705          cat, dev);
04706       return -1;
04707    }
04708 
04709    if (!(trunk = ast_calloc(1, sizeof(*trunk))))
04710       return -1;
04711    if (ast_string_field_init(trunk, 32)) {
04712       free(trunk);
04713       return -1;
04714    }
04715 
04716    ast_string_field_set(trunk, name, cat);
04717    ast_string_field_set(trunk, device, dev);
04718 
04719    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04720       if (!strcasecmp(var->name, "autocontext"))
04721          ast_string_field_set(trunk, autocontext, var->value);
04722       else if (!strcasecmp(var->name, "ringtimeout")) {
04723          if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
04724             ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
04725                var->value, trunk->name);
04726             trunk->ring_timeout = 0;
04727          }
04728       } else if (!strcasecmp(var->name, "barge"))
04729          trunk->barge_disabled = ast_false(var->value);
04730       else if (!strcasecmp(var->name, "hold")) {
04731          if (!strcasecmp(var->value, "private"))
04732             trunk->hold_access = SLA_HOLD_PRIVATE;
04733          else if (!strcasecmp(var->value, "open"))
04734             trunk->hold_access = SLA_HOLD_OPEN;
04735          else {
04736             ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
04737                var->value, trunk->name);
04738          }
04739       } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
04740          ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
04741             var->name, var->lineno, SLA_CONFIG_FILE);
04742       }
04743    }
04744 
04745    if (!ast_strlen_zero(trunk->autocontext)) {
04746       struct ast_context *context;
04747       context = ast_context_find_or_create(NULL, trunk->autocontext, sla_registrar);
04748       if (!context) {
04749          ast_log(LOG_ERROR, "Failed to automatically find or create "
04750             "context '%s' for SLA!\n", trunk->autocontext);
04751          destroy_trunk(trunk);
04752          return -1;
04753       }
04754       if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
04755          NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
04756          ast_log(LOG_ERROR, "Failed to automatically create extension "
04757             "for trunk '%s'!\n", trunk->name);
04758          destroy_trunk(trunk);
04759          return -1;
04760       }
04761    }
04762 
04763    AST_RWLIST_WRLOCK(&sla_trunks);
04764    AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
04765    AST_RWLIST_UNLOCK(&sla_trunks);
04766 
04767    return 0;
04768 }

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

04039 {
04040    struct sla_station *station;
04041    int res = 0;
04042 
04043    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04044       struct sla_ringing_trunk *ringing_trunk;
04045       int time_left;
04046 
04047       /* Ignore stations already ringing */
04048       if (sla_check_ringing_station(station))
04049          continue;
04050 
04051       /* Ignore stations already on a call */
04052       if (sla_check_inuse_station(station))
04053          continue;
04054 
04055       /* Ignore stations that don't have one of their trunks ringing */
04056       if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
04057          continue;
04058 
04059       if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
04060          continue;
04061 
04062       /* If there is no time left, then the station needs to start ringing.
04063        * Return non-zero so that an event will be queued up an event to 
04064        * make that happen. */
04065       if (time_left <= 0) {
04066          res = 1;
04067          continue;
04068       }
04069 
04070       if (time_left < *timeout)
04071          *timeout = time_left;
04072    }
04073 
04074    return res;
04075 }

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

03956 {
03957    struct sla_ringing_trunk *ringing_trunk;
03958    struct sla_ringing_station *ringing_station;
03959    int res = 0;
03960 
03961    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03962       unsigned int ring_timeout = 0;
03963       int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
03964       struct sla_trunk_ref *trunk_ref;
03965 
03966       /* If there are any ring timeouts specified for a specific trunk
03967        * on the station, then use the highest per-trunk ring timeout.
03968        * Otherwise, use the ring timeout set for the entire station. */
03969       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03970          struct sla_station_ref *station_ref;
03971          int trunk_time_elapsed, trunk_time_left;
03972 
03973          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03974             if (ringing_trunk->trunk == trunk_ref->trunk)
03975                break;
03976          }
03977          if (!ringing_trunk)
03978             continue;
03979 
03980          /* If there is a trunk that is ringing without a timeout, then the
03981           * only timeout that could matter is a global station ring timeout. */
03982          if (!trunk_ref->ring_timeout)
03983             break;
03984 
03985          /* This trunk on this station is ringing and has a timeout.
03986           * However, make sure this trunk isn't still ringing from a
03987           * previous timeout.  If so, don't consider it. */
03988          AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
03989             if (station_ref->station == ringing_station->station)
03990                break;
03991          }
03992          if (station_ref)
03993             continue;
03994 
03995          trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03996          trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
03997          if (trunk_time_left > final_trunk_time_left)
03998             final_trunk_time_left = trunk_time_left;
03999       }
04000 
04001       /* No timeout was found for ringing trunks, and no timeout for the entire station */
04002       if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
04003          continue;
04004 
04005       /* Compute how much time is left for a global station timeout */
04006       if (ringing_station->station->ring_timeout) {
04007          ring_timeout = ringing_station->station->ring_timeout;
04008          time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
04009          time_left = (ring_timeout * 1000) - time_elapsed;
04010       }
04011 
04012       /* If the time left based on the per-trunk timeouts is smaller than the
04013        * global station ring timeout, use that. */
04014       if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
04015          time_left = final_trunk_time_left;
04016 
04017       /* If there is no time left, the station needs to stop ringing */
04018       if (time_left <= 0) {
04019          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
04020          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
04021          res = 1;
04022          continue;
04023       }
04024 
04025       /* There is still some time left for this station to ring, so save that
04026        * timeout if it is the first event scheduled to occur */
04027       if (time_left < *timeout)
04028          *timeout = time_left;
04029    }
04030    AST_LIST_TRAVERSE_SAFE_END
04031 
04032    return res;
04033 }

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

03926 {
03927    struct sla_ringing_trunk *ringing_trunk;
03928    int res = 0;
03929 
03930    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03931       int time_left, time_elapsed;
03932       if (!ringing_trunk->trunk->ring_timeout)
03933          continue;
03934       time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03935       time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
03936       if (time_left <= 0) {
03937          pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
03938          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03939          sla_stop_ringing_trunk(ringing_trunk);
03940          res = 1;
03941          continue;
03942       }
03943       if (time_left < *timeout)
03944          *timeout = time_left;
03945    }
03946    AST_LIST_TRAVERSE_SAFE_END
03947 
03948    return res;
03949 }

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

03392 {
03393    struct sla_station *station;
03394    struct sla_trunk_ref *trunk_ref;
03395 
03396    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
03397       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03398          if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
03399             || trunk_ref == exclude)
03400             continue;
03401          trunk_ref->state = state;
03402          ast_device_state_changed("SLA:%s_%s", station->name, trunk->name);
03403          break;
03404       }
03405    }
03406 }

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

Definition at line 4679 of file app_meetme.c.

References ast_strdupa, and ast_strlen_zero().

Referenced by sla_build_trunk().

04680 {
04681    char *tech, *tech_data;
04682 
04683    tech_data = ast_strdupa(device);
04684    tech = strsep(&tech_data, "/");
04685 
04686    if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
04687       return -1;
04688 
04689    return 0;
04690 }

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

03674 {
03675    struct sla_failed_station *failed_station;
03676    int res = 0;
03677 
03678    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
03679       if (station != failed_station->station)
03680          continue;
03681       if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
03682          AST_LIST_REMOVE_CURRENT(&sla.failed_stations, entry);
03683          free(failed_station);
03684          break;
03685       }
03686       res = 1;
03687    }
03688    AST_LIST_TRAVERSE_SAFE_END
03689 
03690    return res;
03691 }

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

Check to see if a station is in use.

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

03760 {
03761    struct sla_trunk_ref *trunk_ref;
03762 
03763    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03764       if (trunk_ref->chan)
03765          return 1;
03766    }
03767 
03768    return 0;
03769 }

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

03659 {
03660    struct sla_ringing_station *ringing_station;
03661 
03662    AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
03663       if (station == ringing_station->station)
03664          return 1;
03665    }
03666 
03667    return 0;
03668 }

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

03791 {
03792    struct sla_trunk_ref *trunk_ref;
03793    unsigned int delay = UINT_MAX;
03794    int time_left, time_elapsed;
03795 
03796    if (!ringing_trunk)
03797       ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
03798    else
03799       trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
03800 
03801    if (!ringing_trunk || !trunk_ref)
03802       return delay;
03803 
03804    /* If this station has a ring delay specific to the highest priority
03805     * ringing trunk, use that.  Otherwise, use the ring delay specified
03806     * globally for the station. */
03807    delay = trunk_ref->ring_delay;
03808    if (!delay)
03809       delay = station->ring_delay;
03810    if (!delay)
03811       return INT_MAX;
03812 
03813    time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
03814    time_left = (delay * 1000) - time_elapsed;
03815 
03816    return time_left;
03817 }

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

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

03314 {
03315    struct sla_station_ref *station_ref;
03316    struct sla_trunk_ref *trunk_ref;
03317 
03318    /* For each station that has this call on hold, check for private hold. */
03319    AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03320       AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03321          if (trunk_ref->trunk != trunk || station_ref->station == station)
03322             continue;
03323          if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03324             station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03325             return 1;
03326          return 0;
03327       }
03328    }
03329 
03330    return 0;
03331 }

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

03526 {
03527    struct sla_station_ref *timed_out_station;
03528 
03529    AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
03530       if (station == timed_out_station->station)
03531          return 1;
03532    }
03533 
03534    return 0;
03535 }

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

04290 {
04291    struct sla_trunk_ref *trunk_ref = NULL;
04292 
04293    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04294       if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
04295          break;
04296    }
04297 
04298    return trunk_ref;
04299 }

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

03547 {
03548    struct sla_trunk_ref *s_trunk_ref;
03549    struct sla_ringing_trunk *ringing_trunk = NULL;
03550 
03551    AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
03552       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
03553          /* Make sure this is the trunk we're looking for */
03554          if (s_trunk_ref->trunk != ringing_trunk->trunk)
03555             continue;
03556 
03557          /* This trunk on the station is ringing.  But, make sure this station
03558           * didn't already time out while this trunk was ringing. */
03559          if (sla_check_timed_out_station(ringing_trunk, station))
03560             continue;
03561 
03562          if (remove)
03563             AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
03564 
03565          if (trunk_ref)
03566             *trunk_ref = s_trunk_ref;
03567 
03568          break;
03569       }
03570       AST_LIST_TRAVERSE_SAFE_END
03571    
03572       if (ringing_trunk)
03573          break;
03574    }
03575 
03576    return ringing_trunk;
03577 }

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

Definition at line 3377 of file app_meetme.c.

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

Referenced by sla_ring_station().

03378 {
03379    struct sla_ringing_station *ringing_station;
03380 
03381    if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
03382       return NULL;
03383 
03384    ringing_station->station = station;
03385    ringing_station->ring_begin = ast_tvnow();
03386 
03387    return ringing_station;
03388 }

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

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

03366 {
03367    struct sla_station_ref *station_ref;
03368 
03369    if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
03370       return NULL;
03371 
03372    station_ref->station = station;
03373 
03374    return station_ref;
03375 }

static void sla_destroy ( void   )  [static]

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

04650 {
04651    struct sla_trunk *trunk;
04652    struct sla_station *station;
04653 
04654    AST_RWLIST_WRLOCK(&sla_trunks);
04655    while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
04656       destroy_trunk(trunk);
04657    AST_RWLIST_UNLOCK(&sla_trunks);
04658 
04659    AST_RWLIST_WRLOCK(&sla_stations);
04660    while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
04661       destroy_station(station);
04662    AST_RWLIST_UNLOCK(&sla_stations);
04663 
04664    if (sla.thread != AST_PTHREADT_NULL) {
04665       ast_mutex_lock(&sla.lock);
04666       sla.stop = 1;
04667       ast_cond_signal(&sla.cond);
04668       ast_mutex_unlock(&sla.lock);
04669       pthread_join(sla.thread, NULL);
04670    }
04671 
04672    /* Drop any created contexts from the dialplan */
04673    ast_context_destroy(NULL, sla_registrar);
04674 
04675    ast_mutex_destroy(&sla.lock);
04676    ast_cond_destroy(&sla.cond);
04677 }

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 3516 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

03517 {
03518    sla_queue_event(SLA_EVENT_DIAL_STATE);
03519 }

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

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

Referenced by sla_station_exec().

03301 {
03302    struct sla_station *station = NULL;
03303 
03304    AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03305       if (!strcasecmp(station->name, name))
03306          break;
03307    }
03308 
03309    return station;
03310 }

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

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

Referenced by sla_trunk_exec().

03286 {
03287    struct sla_trunk *trunk = NULL;
03288 
03289    AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03290       if (!strcasecmp(trunk->name, name))
03291          break;
03292    }
03293 
03294    return trunk;
03295 }

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

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

03773 {
03774    struct sla_trunk_ref *trunk_ref = NULL;
03775 
03776    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03777       if (trunk_ref->trunk == trunk)
03778          break;
03779    }
03780 
03781    return trunk_ref;
03782 }

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

03342 {
03343    struct sla_trunk_ref *trunk_ref = NULL;
03344 
03345    AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03346       if (strcasecmp(trunk_ref->trunk->name, name))
03347          continue;
03348 
03349       if ( (trunk_ref->trunk->barge_disabled 
03350          && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
03351          (trunk_ref->trunk->hold_stations 
03352          && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
03353          && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
03354          sla_check_station_hold_access(trunk_ref->trunk, station) ) 
03355       {
03356          trunk_ref = NULL;
03357       }
03358 
03359       break;
03360    }
03361 
03362    return trunk_ref;
03363 }

static void sla_handle_dial_state_event ( void   )  [static]

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

03580 {
03581    struct sla_ringing_station *ringing_station;
03582 
03583    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03584       struct sla_trunk_ref *s_trunk_ref = NULL;
03585       struct sla_ringing_trunk *ringing_trunk = NULL;
03586       struct run_station_args args;
03587       enum ast_dial_result dial_res;
03588       pthread_attr_t attr;
03589       pthread_t dont_care;
03590       ast_mutex_t cond_lock;
03591       ast_cond_t cond;
03592 
03593       switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
03594       case AST_DIAL_RESULT_HANGUP:
03595       case AST_DIAL_RESULT_INVALID:
03596       case AST_DIAL_RESULT_FAILED:
03597       case AST_DIAL_RESULT_TIMEOUT:
03598       case AST_DIAL_RESULT_UNANSWERED:
03599          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03600          sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
03601          break;
03602       case AST_DIAL_RESULT_ANSWERED:
03603          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03604          /* Find the appropriate trunk to answer. */
03605          ast_mutex_lock(&sla.lock);
03606          ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
03607          ast_mutex_unlock(&sla.lock);
03608          if (!ringing_trunk) {
03609             ast_log(LOG_DEBUG, "Found no ringing trunk for station '%s' to answer!\n",
03610                ringing_station->station->name);
03611             break;
03612          }
03613          /* Track the channel that answered this trunk */
03614          s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
03615          /* Actually answer the trunk */
03616          answer_trunk_chan(ringing_trunk->trunk->chan);
03617          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
03618          /* Now, start a thread that will connect this station to the trunk.  The rest of
03619           * the code here sets up the thread and ensures that it is able to save the arguments
03620           * before they are no longer valid since they are allocated on the stack. */
03621          args.trunk_ref = s_trunk_ref;
03622          args.station = ringing_station->station;
03623          args.cond = &cond;
03624          args.cond_lock = &cond_lock;
03625          free(ringing_trunk);
03626          free(ringing_station);
03627          ast_mutex_init(&cond_lock);
03628          ast_cond_init(&cond, NULL);
03629          pthread_attr_init(&attr);
03630          pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
03631          ast_mutex_lock(&cond_lock);
03632          ast_pthread_create_background(&dont_care, &attr, run_station, &args);
03633          ast_cond_wait(&cond, &cond_lock);
03634          ast_mutex_unlock(&cond_lock);
03635          ast_mutex_destroy(&cond_lock);
03636          ast_cond_destroy(&cond);
03637          pthread_attr_destroy(&attr);
03638          break;
03639       case AST_DIAL_RESULT_TRYING:
03640       case AST_DIAL_RESULT_RINGING:
03641       case AST_DIAL_RESULT_PROGRESS:
03642       case AST_DIAL_RESULT_PROCEEDING:
03643          break;
03644       }
03645       if (dial_res == AST_DIAL_RESULT_ANSWERED) {
03646          /* Queue up reprocessing ringing trunks, and then ringing stations again */
03647          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
03648          sla_queue_event(SLA_EVENT_DIAL_STATE);
03649          break;
03650       }
03651    }
03652    AST_LIST_TRAVERSE_SAFE_END
03653 }

static void sla_handle_hold_event ( struct sla_event event  )  [static]

Definition at line 3901 of file app_meetme.c.

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

Referenced by sla_thread().

03902 {
03903    ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
03904    event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
03905    ast_device_state_changed("SLA:%s_%s", 
03906       event->station->name, event->trunk_ref->trunk->name);
03907    sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, 
03908       INACTIVE_TRUNK_REFS, event->trunk_ref);
03909 
03910    if (event->trunk_ref->trunk->active_stations == 1) {
03911       /* The station putting it on hold is the only one on the call, so start
03912        * Music on hold to the trunk. */
03913       event->trunk_ref->trunk->on_hold = 1;
03914       ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
03915    }
03916 
03917    ast_softhangup(event->trunk_ref->chan, AST_CAUSE_NORMAL);
03918    event->trunk_ref->chan = NULL;
03919 }

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 3891 of file app_meetme.c.

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

Referenced by sla_thread().

03892 {
03893    ast_mutex_lock(&sla.lock);
03894    sla_ring_stations();
03895    ast_mutex_unlock(&sla.lock);
03896 
03897    /* Find stations that shouldn't be ringing anymore. */
03898    sla_hangup_stations();
03899 }

static void sla_hangup_stations ( void   )  [static]

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

03864 {
03865    struct sla_trunk_ref *trunk_ref;
03866    struct sla_ringing_station *ringing_station;
03867 
03868    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
03869       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03870          struct sla_ringing_trunk *ringing_trunk;
03871          ast_mutex_lock(&sla.lock);
03872          AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03873             if (trunk_ref->trunk == ringing_trunk->trunk)
03874                break;
03875          }
03876          ast_mutex_unlock(&sla.lock);
03877          if (ringing_trunk)
03878             break;
03879       }
03880       if (!trunk_ref) {
03881          AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
03882          ast_dial_join(ringing_station->station->dial);
03883          ast_dial_destroy(ringing_station->station->dial);
03884          ringing_station->station->dial = NULL;
03885          free(ringing_station);
03886       }
03887    }
03888    AST_LIST_TRAVERSE_SAFE_END
03889 }

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

Definition at line 1070 of file app_meetme.c.

References SLA_HOLD_OPEN, and SLA_HOLD_PRIVATE.

Referenced by sla_show_stations(), and sla_show_trunks().

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

static int sla_load_config ( void   )  [static]

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

04936 {
04937    struct ast_config *cfg;
04938    const char *cat = NULL;
04939    int res = 0;
04940    const char *val;
04941 
04942    ast_mutex_init(&sla.lock);
04943    ast_cond_init(&sla.cond, NULL);
04944 
04945    if (!(cfg = ast_config_load(SLA_CONFIG_FILE)))
04946       return 0; /* Treat no config as normal */
04947 
04948    if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
04949       sla.attempt_callerid = ast_true(val);
04950 
04951    while ((cat = ast_category_browse(cfg, cat)) && !res) {
04952       const char *type;
04953       if (!strcasecmp(cat, "general"))
04954          continue;
04955       if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
04956          ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
04957             SLA_CONFIG_FILE);
04958          continue;
04959       }
04960       if (!strcasecmp(type, "trunk"))
04961          res = sla_build_trunk(cfg, cat);
04962       else if (!strcasecmp(type, "station"))
04963          res = sla_build_station(cfg, cat);
04964       else {
04965          ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
04966             SLA_CONFIG_FILE, type);
04967       }
04968    }
04969 
04970    ast_config_destroy(cfg);
04971 
04972    if (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations))
04973       ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
04974 
04975    return res;
04976 }

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

04080 {
04081    unsigned int timeout = UINT_MAX;
04082    struct timeval tv;
04083    unsigned int change_made = 0;
04084 
04085    /* Check for ring timeouts on ringing trunks */
04086    if (sla_calc_trunk_timeouts(&timeout))
04087       change_made = 1;
04088 
04089    /* Check for ring timeouts on ringing stations */
04090    if (sla_calc_station_timeouts(&timeout))
04091       change_made = 1;
04092 
04093    /* Check for station ring delays */
04094    if (sla_calc_station_delays(&timeout))
04095       change_made = 1;
04096 
04097    /* queue reprocessing of ringing trunks */
04098    if (change_made)
04099       sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
04100 
04101    /* No timeout */
04102    if (timeout == UINT_MAX)
04103       return 0;
04104 
04105    if (ts) {
04106       tv = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
04107       ts->tv_sec = tv.tv_sec;
04108       ts->tv_nsec = tv.tv_usec * 1000;
04109    }
04110 
04111    return 1;
04112 }

static void sla_queue_event ( enum sla_event_type  type  )  [static]

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

01365 {
01366    sla_queue_event_full(type, NULL, NULL, 1);
01367 }

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

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

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

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

static void sla_queue_event_nolock ( enum sla_event_type  type  )  [static]

Definition at line 1359 of file app_meetme.c.

References sla_queue_event_full().

Referenced by sla_process_timers().

01360 {
01361    sla_queue_event_full(type, NULL, NULL, 0);
01362 }

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

03697 {
03698    char *tech, *tech_data;
03699    struct ast_dial *dial;
03700    struct sla_ringing_station *ringing_station;
03701    const char *cid_name = NULL, *cid_num = NULL;
03702    enum ast_dial_result res;
03703 
03704    if (!(dial = ast_dial_create()))
03705       return -1;
03706 
03707    ast_dial_set_state_callback(dial, sla_dial_state_callback);
03708    tech_data = ast_strdupa(station->device);
03709    tech = strsep(&tech_data, "/");
03710 
03711    if (ast_dial_append(dial, tech, tech_data) == -1) {
03712       ast_dial_destroy(dial);
03713       return -1;
03714    }
03715 
03716    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
03717       cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
03718       free(ringing_trunk->trunk->chan->cid.cid_name);
03719       ringing_trunk->trunk->chan->cid.cid_name = NULL;
03720    }
03721    if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
03722       cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
03723       free(ringing_trunk->trunk->chan->cid.cid_num);
03724       ringing_trunk->trunk->chan->cid.cid_num = NULL;
03725    }
03726 
03727    res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
03728    
03729    if (cid_name)
03730       ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
03731    if (cid_num)
03732       ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
03733    
03734    if (res != AST_DIAL_RESULT_TRYING) {
03735       struct sla_failed_station *failed_station;
03736       ast_dial_destroy(dial);
03737       if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
03738          return -1;
03739       failed_station->station = station;
03740       failed_station->last_try = ast_tvnow();
03741       AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
03742       return -1;
03743    }
03744    if (!(ringing_station = sla_create_ringing_station(station))) {
03745       ast_dial_join(dial);
03746       ast_dial_destroy(dial);
03747       return -1;
03748    }
03749 
03750    station->dial = dial;
03751 
03752    AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
03753 
03754    return 0;
03755 }

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

03823 {
03824    struct sla_station_ref *station_ref;
03825    struct sla_ringing_trunk *ringing_trunk;
03826 
03827    /* Make sure that every station that uses at least one of the ringing
03828     * trunks, is ringing. */
03829    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03830       AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
03831          int time_left;
03832 
03833          /* Is this station already ringing? */
03834          if (sla_check_ringing_station(station_ref->station))
03835             continue;
03836 
03837          /* Is this station already in a call? */
03838          if (sla_check_inuse_station(station_ref->station))
03839             continue;
03840 
03841          /* Did we fail to dial this station earlier?  If so, has it been
03842           * a minute since we tried? */
03843          if (sla_check_failed_station(station_ref->station))
03844             continue;
03845 
03846          /* If this station already timed out while this trunk was ringing,
03847           * do not dial it again for this ringing trunk. */
03848          if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
03849             continue;
03850 
03851          /* Check for a ring delay in progress */
03852          time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
03853          if (time_left != INT_MAX && time_left > 0)
03854             continue;
03855 
03856          /* It is time to make this station begin to ring.  Do it! */
03857          sla_ring_station(ringing_trunk, station_ref->station);
03858       }
03859    }
03860    /* Now, all of the stations that should be ringing, are ringing. */
03861 }

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

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

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

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

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

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

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

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

04560 {
04561    char *buf, *station_name, *trunk_name;
04562    struct sla_station *station;
04563    struct sla_trunk_ref *trunk_ref;
04564    int res = AST_DEVICE_INVALID;
04565 
04566    trunk_name = buf = ast_strdupa(data);
04567    station_name = strsep(&trunk_name, "_");
04568 
04569    AST_RWLIST_RDLOCK(&sla_stations);
04570    AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04571       if (strcasecmp(station_name, station->name))
04572          continue;
04573       AST_RWLIST_RDLOCK(&sla_trunks);
04574       AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04575          if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
04576             break;
04577       }
04578       if (!trunk_ref) {
04579          AST_RWLIST_UNLOCK(&sla_trunks);
04580          break;
04581       }
04582       switch (trunk_ref->state) {
04583       case SLA_TRUNK_STATE_IDLE:
04584          res = AST_DEVICE_NOT_INUSE;
04585          break;
04586       case SLA_TRUNK_STATE_RINGING:
04587          res = AST_DEVICE_RINGING;
04588          break;
04589       case SLA_TRUNK_STATE_UP:
04590          res = AST_DEVICE_INUSE;
04591          break;
04592       case SLA_TRUNK_STATE_ONHOLD:
04593       case SLA_TRUNK_STATE_ONHOLD_BYME:
04594          res = AST_DEVICE_ONHOLD;
04595          break;
04596       }
04597       AST_RWLIST_UNLOCK(&sla_trunks);
04598    }
04599    AST_RWLIST_UNLOCK(&sla_stations);
04600 
04601    if (res == AST_DEVICE_INVALID) {
04602       ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
04603          trunk_name, station_name);
04604    }
04605 
04606    return res;
04607 }

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

Definition at line 4301 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, dial_trunk_args::cond_lock, 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().

04302 {
04303    char *station_name, *trunk_name;
04304    struct sla_station *station;
04305    struct sla_trunk_ref *trunk_ref = NULL;
04306    char conf_name[MAX_CONFNUM];
04307    struct ast_flags conf_flags = { 0 };
04308    struct ast_conference *conf;
04309 
04310    if (ast_strlen_zero(data)) {
04311       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04312       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04313       return 0;
04314    }
04315 
04316    trunk_name = ast_strdupa(data);
04317    station_name = strsep(&trunk_name, "_");
04318 
04319    if (ast_strlen_zero(station_name)) {
04320       ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
04321       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04322       return 0;
04323    }
04324 
04325    AST_RWLIST_RDLOCK(&sla_stations);
04326    station = sla_find_station(station_name);
04327    AST_RWLIST_UNLOCK(&sla_stations);
04328 
04329    if (!station) {
04330       ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
04331       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
04332       return 0;
04333    }
04334 
04335    AST_RWLIST_RDLOCK(&sla_trunks);
04336    if (!ast_strlen_zero(trunk_name)) {
04337       trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
04338    } else
04339       trunk_ref = sla_choose_idle_trunk(station);
04340    AST_RWLIST_UNLOCK(&sla_trunks);
04341 
04342    if (!trunk_ref) {
04343       if (ast_strlen_zero(trunk_name))
04344          ast_log(LOG_NOTICE, "No trunks available for call.\n");
04345       else {
04346          ast_log(LOG_NOTICE, "Can't join existing call on trunk "
04347             "'%s' due to access controls.\n", trunk_name);
04348       }
04349       pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
04350       return 0;
04351    }
04352 
04353    if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
04354       if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
04355          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04356       else {
04357          trunk_ref->state = SLA_TRUNK_STATE_UP;
04358          ast_device_state_changed("SLA:%s_%s", station->name, trunk_ref->trunk->name);
04359       }
04360    } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
04361       struct sla_ringing_trunk *ringing_trunk;
04362 
04363       ast_mutex_lock(&sla.lock);
04364       AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04365          if (ringing_trunk->trunk == trunk_ref->trunk) {
04366             AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
04367             break;
04368          }
04369       }
04370       AST_LIST_TRAVERSE_SAFE_END
04371       ast_mutex_unlock(&sla.lock);
04372 
04373       if (ringing_trunk) {
04374          answer_trunk_chan(ringing_trunk->trunk->chan);
04375          sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04376 
04377          free(ringing_trunk);
04378 
04379          /* Queue up reprocessing ringing trunks, and then ringing stations again */
04380          sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04381          sla_queue_event(SLA_EVENT_DIAL_STATE);
04382       }
04383    }
04384 
04385    trunk_ref->chan = chan;
04386 
04387    if (!trunk_ref->trunk->chan) {
04388       ast_mutex_t cond_lock;
04389       ast_cond_t cond;
04390       pthread_t dont_care;
04391       pthread_attr_t attr;
04392       struct dial_trunk_args args = {
04393          .trunk_ref = trunk_ref,
04394          .station = station,
04395          .cond_lock = &cond_lock,
04396          .cond = &cond,
04397       };
04398       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04399       /* Create a thread to dial the trunk and dump it into the conference.
04400        * However, we want to wait until the trunk has been dialed and the
04401        * conference is created before continuing on here. */
04402       ast_autoservice_start(chan);
04403       ast_mutex_init(&cond_lock);
04404       ast_cond_init(&cond, NULL);
04405       pthread_attr_init(&attr);
04406       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04407       ast_mutex_lock(&cond_lock);
04408       ast_pthread_create_background(&dont_care, &attr, dial_trunk, &args);
04409       ast_cond_wait(&cond, &cond_lock);
04410       ast_mutex_unlock(&cond_lock);
04411       ast_mutex_destroy(&cond_lock);
04412       ast_cond_destroy(&cond);
04413       pthread_attr_destroy(&attr);
04414       ast_autoservice_stop(chan);
04415       if (!trunk_ref->trunk->chan) {
04416          ast_log(LOG_DEBUG, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
04417          pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
04418          sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04419          trunk_ref->chan = NULL;
04420          return 0;
04421       }
04422    }
04423 
04424    if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
04425       trunk_ref->trunk->on_hold) {
04426       trunk_ref->trunk->on_hold = 0;
04427       ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
04428       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04429    }
04430 
04431    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04432    ast_set_flag(&conf_flags, 
04433       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04434    ast_answer(chan);
04435    conf = build_conf(conf_name, "", "", 0, 0, 1);
04436    if (conf) {
04437       conf_run(chan, conf, conf_flags.flags, NULL);
04438       dispose_conf(conf);
04439       conf = NULL;
04440    }
04441    trunk_ref->chan = NULL;
04442    if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04443       trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04444       strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
04445       admin_exec(NULL, conf_name);
04446       trunk_ref->trunk->hold_stations = 0;
04447       sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04448    }
04449    
04450    pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
04451 
04452    return 0;
04453 }

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

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

03483 {
03484    struct sla_ringing_trunk *ringing_trunk;
03485    struct sla_trunk_ref *trunk_ref;
03486    struct sla_station_ref *station_ref;
03487 
03488    ast_dial_join(ringing_station->station->dial);
03489    ast_dial_destroy(ringing_station->station->dial);
03490    ringing_station->station->dial = NULL;
03491 
03492    if (hangup == SLA_STATION_HANGUP_NORMAL)
03493       goto done;
03494 
03495    /* If the station is being hung up because of a timeout, then add it to the
03496     * list of timed out stations on each of the ringing trunks.  This is so
03497     * that when doing further processing to figure out which stations should be
03498     * ringing, which trunk to answer, determining timeouts, etc., we know which
03499     * ringing trunks we should ignore. */
03500    AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
03501       AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
03502          if (ringing_trunk->trunk == trunk_ref->trunk)
03503             break;
03504       }
03505       if (!trunk_ref)
03506          continue;
03507       if (!(station_ref = sla_create_station_ref(ringing_station->station)))
03508          continue;
03509       AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
03510    }
03511 
03512 done:
03513    free(ringing_station);
03514 }

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

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

03467 {
03468    char buf[80];
03469    struct sla_station_ref *station_ref;
03470 
03471    snprintf(buf, sizeof(buf), "SLA_%s|K", ringing_trunk->trunk->name);
03472    admin_exec(NULL, buf);
03473    sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
03474 
03475    while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
03476       free(station_ref);
03477 
03478    free(ringing_trunk);
03479 }

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

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

04115 {
04116    struct sla_failed_station *failed_station;
04117    struct sla_ringing_station *ringing_station;
04118 
04119    ast_mutex_lock(&sla.lock);
04120 
04121    while (!sla.stop) {
04122       struct sla_event *event;
04123       struct timespec ts = { 0, };
04124       unsigned int have_timeout = 0;
04125 
04126       if (AST_LIST_EMPTY(&sla.event_q)) {
04127          if ((have_timeout = sla_process_timers(&ts)))
04128             ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
04129          else
04130             ast_cond_wait(&sla.cond, &sla.lock);
04131          if (sla.stop)
04132             break;
04133       }
04134 
04135       if (have_timeout)
04136          sla_process_timers(NULL);
04137 
04138       while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
04139          ast_mutex_unlock(&sla.lock);
04140          switch (event->type) {
04141          case SLA_EVENT_HOLD:
04142             sla_handle_hold_event(event);
04143             break;
04144          case SLA_EVENT_DIAL_STATE:
04145             sla_handle_dial_state_event();
04146             break;
04147          case SLA_EVENT_RINGING_TRUNK:
04148             sla_handle_ringing_trunk_event();
04149             break;
04150          }
04151          free(event);
04152          ast_mutex_lock(&sla.lock);
04153       }
04154    }
04155 
04156    ast_mutex_unlock(&sla.lock);
04157 
04158    while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
04159       free(ringing_station);
04160 
04161    while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
04162       free(failed_station);
04163 
04164    return NULL;
04165 }

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

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

04489 {
04490    const char *trunk_name = data;
04491    char conf_name[MAX_CONFNUM];
04492    struct ast_conference *conf;
04493    struct ast_flags conf_flags = { 0 };
04494    struct sla_trunk *trunk;
04495    struct sla_ringing_trunk *ringing_trunk;
04496 
04497    AST_RWLIST_RDLOCK(&sla_trunks);
04498    trunk = sla_find_trunk(trunk_name);
04499    AST_RWLIST_UNLOCK(&sla_trunks);
04500    if (!trunk) {
04501       ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", trunk_name);
04502       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04503       return 0;
04504    }
04505    if (trunk->chan) {
04506       ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
04507          trunk_name);
04508       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04509       return 0;
04510    }
04511    trunk->chan = chan;
04512 
04513    if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
04514       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04515       return 0;
04516    }
04517 
04518    snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_name);
04519    conf = build_conf(conf_name, "", "", 1, 1, 1);
04520    if (!conf) {
04521       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
04522       return 0;
04523    }
04524    ast_set_flag(&conf_flags, 
04525       CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
04526    ast_indicate(chan, AST_CONTROL_RINGING);
04527    conf_run(chan, conf, conf_flags.flags, NULL);
04528    dispose_conf(conf);
04529    conf = NULL;
04530    trunk->chan = NULL;
04531    trunk->on_hold = 0;
04532 
04533    sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04534 
04535    if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
04536       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
04537 
04538    /* Remove the entry from the list of ringing trunks if it is still there. */
04539    ast_mutex_lock(&sla.lock);
04540    AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04541       if (ringing_trunk->trunk == trunk) {
04542          AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
04543          break;
04544       }
04545    }
04546    AST_LIST_TRAVERSE_SAFE_END
04547    ast_mutex_unlock(&sla.lock);
04548    if (ringing_trunk) {
04549       free(ringing_trunk);
04550       pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
04551       /* Queue reprocessing of ringing trunks to make stations stop ringing
04552        * that shouldn't be ringing after this trunk stopped. */
04553       sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04554    }
04555 
04556    return 0;
04557 }

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

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

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

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

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

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

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

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

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

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

Definition at line 657 of file app_meetme.c.

References volume::desired, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

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

static int unload_module ( void   )  [static]

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

04990 {
04991    int res = 0;
04992    
04993    ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
04994    res = ast_manager_unregister("MeetmeMute");
04995    res |= ast_manager_unregister("MeetmeUnmute");
04996    res |= ast_unregister_application(app3);
04997    res |= ast_unregister_application(app2);
04998    res |= ast_unregister_application(app);
04999    res |= ast_unregister_application(slastation_app);
05000    res |= ast_unregister_application(slatrunk_app);
05001 
05002    ast_devstate_prov_del("Meetme");
05003    ast_devstate_prov_del("SLA");
05004 
05005    ast_module_user_hangup_all();
05006    
05007    sla_destroy();
05008 
05009    return res;
05010 }


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

Definition at line 5046 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 5046 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 563 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 570 of file app_meetme.c.

Referenced by conf_run(), and load_config_meetme().

struct ast_cli_entry cli_meetme[] [static]

Definition at line 1216 of file app_meetme.c.

Referenced by load_module(), and unload_module().

ast_cond_t cond

Definition at line 554 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 381 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 559 of file app_meetme.c.

struct sla_failed_station* first

Definition at line 558 of file app_meetme.c.

struct sla_ringing_station* first

Definition at line 557 of file app_meetme.c.

struct sla_ringing_trunk* first

Definition at line 556 of file app_meetme.c.

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

struct sla_event* last

Definition at line 559 of file app_meetme.c.

struct sla_failed_station* last

Definition at line 558 of file app_meetme.c.

struct sla_ringing_station* last

Definition at line 557 of file app_meetme.c.

struct sla_ringing_trunk* last

Definition at line 556 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 555 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 1066 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 499 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 1212 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 1143 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 560 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 553 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 Oct 1 13:09:13 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7