Wed Feb 11 12:00:03 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 << 28)
}
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 = "f450f61f60e761b3aa089ebed76ca8a5" , .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 

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    /* Arbitrary Intro message */
00171    CONFFLAG_INTROMSG = (1 << 28),
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 5049 of file app_meetme.c.

static void __unreg_module ( void   )  [static]

Definition at line 5049 of file app_meetme.c.

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

Definition at line 3162 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03163 {
03164    return meetmemute(s, m, 1);
03165 }

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

Definition at line 3167 of file app_meetme.c.

References meetmemute(), and s.

Referenced by load_module().

03168 {
03169    return meetmemute(s, m, 0);
03170 }

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

The MeetMeadmin application.

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

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

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

03419 {
03420    ast_answer(chan);
03421    ast_indicate(chan, -1);
03422 }

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, "%d", &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 2685 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.

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

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

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

The MeetmeCount application.

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

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

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

Definition at line 4458 of file app_meetme.c.

References ast_calloc, and sla_trunk_ref::trunk.

Referenced by sla_add_trunk_to_station().

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

static void destroy_station ( struct sla_station station  )  [static]

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

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

static void destroy_trunk ( struct sla_trunk trunk  )  [static]

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

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

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

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

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

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, "%d", &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 2540 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().

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

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

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

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

Definition at line 2931 of file app_meetme.c.

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

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

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

References load_config_meetme(), and sla_load_config().

04982 {
04983    int res = 0;
04984 
04985    load_config_meetme();
04986    if (!reload)
04987       res = sla_load_config();
04988 
04989    return res;
04990 }

static void load_config_meetme ( void   )  [static]

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

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

static int load_module ( void   )  [static]

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

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

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

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

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

Callback for devicestate providers.

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

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

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

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

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

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

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

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

static int reload ( void   )  [static]

Definition at line 5040 of file app_meetme.c.

References load_config().

05041 {
05042    return load_config(1);
05043 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 4682 of file app_meetme.c.

References ast_strdupa, and ast_strlen_zero().

Referenced by sla_build_trunk().

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

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

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

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

Check to see if a station is in use.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 3380 of file app_meetme.c.

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

Referenced by sla_ring_station().

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

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

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

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

static void sla_destroy ( void   )  [static]

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

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

static void sla_dial_state_callback ( struct ast_dial dial  )  [static]

Definition at line 3519 of file app_meetme.c.

References SLA_EVENT_DIAL_STATE, and sla_queue_event().

Referenced by sla_ring_station().

03520 {
03521    sla_queue_event(SLA_EVENT_DIAL_STATE);
03522 }

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

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

Referenced by sla_station_exec().

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

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

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

Referenced by sla_trunk_exec().

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

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

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

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

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

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

static void sla_handle_dial_state_event ( void   )  [static]

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

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

static void sla_handle_hold_event ( struct sla_event event  )  [static]

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

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

static void sla_handle_ringing_trunk_event ( void   )  [static]

Definition at line 3894 of file app_meetme.c.

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

Referenced by sla_thread().

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

static void sla_hangup_stations ( void   )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 4304 of file app_meetme.c.

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

Referenced by load_module().

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

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

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

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

static void sla_stop_ringing_trunk ( struct sla_ringing_trunk ringing_trunk  )  [static]

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

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

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

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

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

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

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

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

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

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


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

Definition at line 5049 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 5049 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 Wed Feb 11 12:00:03 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7