Asterisk - The Open Source Telephony Project GIT-master-1f1c5bb
Data Structures | Macros | Enumerations | Functions | Variables
app_meetme.c File Reference

Meet me conference bridge. More...

#include "asterisk.h"
#include <dahdi/user.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/astobj2.h"
#include "asterisk/devicestate.h"
#include "asterisk/dial.h"
#include "asterisk/causes.h"
#include "asterisk/paths.h"
#include "asterisk/test.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_message_router.h"
#include "asterisk/json.h"
#include "asterisk/format_compatibility.h"
#include "enter.h"
#include "leave.h"
Include dependency graph for app_meetme.c:

Go to the source code of this file.

Data Structures

struct  announce_listitem
 
struct  ast_conf_user
 The MeetMe User object. More...
 
struct  ast_conference
 The MeetMe Conference object. More...
 
struct  confs
 
struct  volume
 

Macros

#define AST_FRAME_BITS   32
 
#define CONF_SIZE   320
 
#define CONFFLAG_DONT_DENOISE   (1ULL << 35)
 
#define CONFFLAG_INTROMSG   (1ULL << 32)
 
#define CONFFLAG_INTROUSER_VMREC   (1ULL << 33)
 
#define CONFFLAG_KILL_LAST_MAN_STANDING   (1ULL << 34)
 
#define CONFFLAG_NO_AUDIO_UNTIL_UP   (1ULL << 31)
 
#define CONFIG_FILE_NAME   "meetme.conf"
 
#define DATE_FORMAT   "%Y-%m-%d %H:%M:%S"
 
#define DEFAULT_AUDIO_BUFFERS   32
 
#define MAX_CONFNUM   80
 
#define MAX_PIN   80
 
#define MAX_SETTINGS   (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)
 
#define MC_DATA_FORMAT   "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
 
#define MC_HEADER_FORMAT   "%-14s %-14s %-10s %-8s %-8s %-6s\n"
 
#define MEETME_DELAYDETECTENDTALK   1000
 
#define MEETME_DELAYDETECTTALK   300
 
#define OPTIONS_LEN   100
 
#define STR_CONCISE   "concise"
 

Enumerations

enum  {
  ADMINFLAG_MUTED = (1 << 1) , ADMINFLAG_SELFMUTED = (1 << 2) , ADMINFLAG_KICKME = (1 << 3) , ADMINFLAG_T_REQUEST = (1 << 4) ,
  ADMINFLAG_HANGUP = (1 << 5)
}
 
enum  {
  CONFFLAG_ADMIN = (1 << 0) , CONFFLAG_MONITOR = (1 << 1) , CONFFLAG_KEYEXIT = (1 << 2) , CONFFLAG_STARMENU = (1 << 3) ,
  CONFFLAG_TALKER = (1 << 4) , CONFFLAG_QUIET = (1 << 5) , CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6) , CONFFLAG_AGI = (1 << 7) ,
  CONFFLAG_MOH = (1 << 8) , CONFFLAG_MARKEDEXIT = (1 << 9) , CONFFLAG_WAITMARKED = (1 << 10) , CONFFLAG_EXIT_CONTEXT = (1 << 11) ,
  CONFFLAG_MARKEDUSER = (1 << 12) , CONFFLAG_INTROUSER = (1 << 13) , CONFFLAG_RECORDCONF = (1<< 14) , CONFFLAG_MONITORTALKER = (1 << 15) ,
  CONFFLAG_DYNAMIC = (1 << 16) , CONFFLAG_DYNAMICPIN = (1 << 17) , CONFFLAG_EMPTY = (1 << 18) , CONFFLAG_EMPTYNOPIN = (1 << 19) ,
  CONFFLAG_ALWAYSPROMPT = (1 << 20) , CONFFLAG_OPTIMIZETALKER = (1 << 21) , CONFFLAG_NOONLYPERSON = (1 << 22) , CONFFLAG_INTROUSERNOREVIEW = (1 << 23) ,
  CONFFLAG_STARTMUTED = (1 << 24) , CONFFLAG_PASS_DTMF = (1 << 25) , CONFFLAG_KICK_CONTINUE = (1 << 26) , CONFFLAG_DURATION_STOP = (1 << 27) ,
  CONFFLAG_DURATION_LIMIT = (1 << 28)
}
 
enum  {
  OPT_ARG_WAITMARKED = 0 , OPT_ARG_EXITKEYS = 1 , OPT_ARG_DURATION_STOP = 2 , OPT_ARG_DURATION_LIMIT = 3 ,
  OPT_ARG_MOH_CLASS = 4 , OPT_ARG_INTROMSG = 5 , OPT_ARG_INTROUSER_VMREC = 6 , OPT_ARG_ARRAY_SIZE = 7
}
 
enum  announcetypes { CONF_HASJOIN , CONF_HASLEFT }
 
enum  entrance_sound { ENTER , LEAVE }
 
enum  menu_modes { MENU_DISABLED = 0 , MENU_NORMAL , MENU_ADMIN , MENU_ADMIN_EXTENDED }
 
enum  recording_state { MEETME_RECORD_OFF , MEETME_RECORD_STARTED , MEETME_RECORD_ACTIVE , MEETME_RECORD_TERMINATE }
 
enum  volume_action { VOL_UP , VOL_DOWN }
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static int acf_meetme_info (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int acf_meetme_info_eval (const char *keyword, const struct ast_conference *conf)
 
static int action_meetmelist (struct mansession *s, const struct message *m)
 
static int action_meetmelistrooms (struct mansession *s, const struct message *m)
 
static int action_meetmemute (struct mansession *s, const struct message *m)
 
static int action_meetmeunmute (struct mansession *s, const struct message *m)
 
static int admin_exec (struct ast_channel *chan, const char *data)
 The MeetMeAdmin application. More...
 
static void * announce_thread (void *data)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static struct ast_conferencebuild_conf (const char *confno, const char *pin, const char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan, struct ast_test *test)
 Find or create a conference. More...
 
static int can_write (struct ast_channel *chan, struct ast_flags64 *confflags)
 
static int careful_write (int fd, unsigned char *data, int len, int block)
 
static int channel_admin_exec (struct ast_channel *chan, const char *data)
 The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command) More...
 
static char * complete_confno (const char *word, int state)
 
static char * complete_meetmecmd_list (const char *line, const char *word, int pos, int state)
 
static char * complete_meetmecmd_lock (const char *word, int pos, int state)
 
static char * complete_meetmecmd_mute_kick (const char *line, const char *word, int pos, int state)
 
static char * complete_userno (struct ast_conference *cnf, const char *word, int state)
 
static int conf_exec (struct ast_channel *chan, const char *data)
 The meetme() application. More...
 
static void conf_flush (int fd, struct ast_channel *chan)
 
static int conf_free (struct ast_conference *conf)
 Remove the conference from the list and free it. More...
 
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, struct ast_flags64 *confflags, char *optargs[])
 
static void conf_start_moh (struct ast_channel *chan, const char *musicclass)
 
static int count_exec (struct ast_channel *chan, const char *data)
 The MeetmeCount application. More...
 
static int dispose_conf (struct ast_conference *conf)
 Decrement reference counts, as incremented by find_conf() More...
 
static void filename_parse (char *filename, char *buffer)
 
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_flags64 *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_flags64 *confflags, int *too_early, char **optargs)
 
static struct ast_conf_userfind_user (struct ast_conference *conf, const char *callerident)
 
static const char * get_announce_filename (enum announcetypes type)
 
static const char * istalking (int x)
 
static int load_config (int reload)
 
static void load_config_meetme (int reload)
 
static int load_module (void)
 Load the module. More...
 
static char * meetme_cmd_helper (struct ast_cli_args *a)
 
static char * meetme_kick_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * meetme_lock_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void meetme_menu (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size, struct ast_format_cap *cap_slin)
 
static void meetme_menu_admin (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
 
static void meetme_menu_admin_extended (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size, struct ast_format_cap *cap_slin)
 
static void meetme_menu_normal (enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
 
static char * meetme_mute_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void meetme_set_defaults (void)
 
static char * meetme_show_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void meetme_stasis_cb (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 
static void meetme_stasis_cleanup (void)
 
static void meetme_stasis_generate_msg (struct ast_conference *meetme_conference, struct ast_channel *chan, struct ast_conf_user *user, struct stasis_message_type *message_type, struct ast_json *extras)
 
static int meetme_stasis_init (void)
 
static int meetmemute (struct mansession *s, const struct message *m, int mute)
 
static enum ast_device_state meetmestate (const char *data)
 Callback for devicestate providers. More...
 
static void * recordthread (void *args)
 
static int reload (void)
 
static void reset_volumes (struct ast_conf_user *user)
 
static int rt_extend_conf (const char *confno)
 
static void send_talking_event (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
 
static int set_listen_volume (struct ast_conf_user *user, int volume)
 
static int set_talk_volume (struct ast_conf_user *user, int volume)
 
static void set_user_talking (struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_end_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_join_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_leave_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_mute_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_talk_request_type)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (meetme_talking_type)
 
static struct ast_jsonstatus_to_json (int on)
 
static void tweak_listen_volume (struct ast_conf_user *user, enum volume_action action)
 
static void tweak_talk_volume (struct ast_conf_user *user, enum volume_action action)
 
static void tweak_volume (struct volume *vol, enum volume_action action)
 
static int unload_module (void)
 
static int user_chan_cb (void *obj, void *args, int flags)
 
static int user_listen_voldown_cb (void *obj, void *unused, int flags)
 
static int user_listen_volup_cb (void *obj, void *unused, int flags)
 
static int user_max_cmp (void *obj, void *arg, int flags)
 
static int user_no_cmp (void *obj, void *arg, int flags)
 
static int user_reset_vol_cb (void *obj, void *unused, int flags)
 
static int user_set_hangup_cb (void *obj, void *check_admin_arg, int flags)
 
static int user_set_kickme_cb (void *obj, void *check_admin_arg, int flags)
 
static int user_set_muted_cb (void *obj, void *check_admin_arg, int flags)
 
static int user_set_unmuted_cb (void *obj, void *check_admin_arg, int flags)
 
static int user_talk_voldown_cb (void *obj, void *unused, int flags)
 
static int user_talk_volup_cb (void *obj, void *unused, int flags)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "MeetMe conference bridge" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_DEPRECATED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, .optional_modules = "func_speex", }
 
static const char *const app = "MeetMe"
 
static const char *const app2 = "MeetMeCount"
 
static const char *const app3 = "MeetMeAdmin"
 
static const char *const app4 = "MeetMeChannelAdmin"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static int audio_buffers
 The number of audio buffers to be allocated on pseudo channels when in a conference. More...
 
static struct ast_cli_entry cli_meetme []
 
static unsigned int conf_map [1024] = {0, }
 
static struct confs confs = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static int earlyalert
 
static int endalert
 
static int extendby
 
static int fuzzystart
 
static const char gain_map []
 Map 'volume' levels from -5 through +5 into decibel (dB) settings for channel drivers. More...
 
static struct stasis_message_routermeetme_event_message_router
 
static struct ast_custom_function meetme_info_acf
 
static const struct ast_app_option meetme_opts [128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'G' ] = { .flag = (1ULL << 32) , .arg_index = OPT_ARG_INTROMSG + 1 }, [ 'v' ] = { .flag = (1ULL << 33) , .arg_index = OPT_ARG_INTROUSER_VMREC + 1 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'k' ] = { .flag = (1ULL << 34) }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'n' ] = { .flag = (1ULL << 35) }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
 
static int rt_log_members
 
static int rt_schedule
 

Detailed Description

Meet me conference bridge.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file app_meetme.c.

Macro Definition Documentation

◆ AST_FRAME_BITS

#define AST_FRAME_BITS   32

Definition at line 676 of file app_meetme.c.

◆ CONF_SIZE

#define CONF_SIZE   320

Definition at line 695 of file app_meetme.c.

◆ CONFFLAG_DONT_DENOISE

#define CONFFLAG_DONT_DENOISE   (1ULL << 35)

If set, don't enable a denoiser for the channel

Definition at line 763 of file app_meetme.c.

◆ CONFFLAG_INTROMSG

#define CONFFLAG_INTROMSG   (1ULL << 32)

If set play an intro announcement at start of conference

Definition at line 758 of file app_meetme.c.

◆ CONFFLAG_INTROUSER_VMREC

#define CONFFLAG_INTROUSER_VMREC   (1ULL << 33)

Definition at line 759 of file app_meetme.c.

◆ CONFFLAG_KILL_LAST_MAN_STANDING

#define CONFFLAG_KILL_LAST_MAN_STANDING   (1ULL << 34)

If there's only one person left in a conference when someone leaves, kill the conference

Definition at line 761 of file app_meetme.c.

◆ CONFFLAG_NO_AUDIO_UNTIL_UP

#define CONFFLAG_NO_AUDIO_UNTIL_UP   (1ULL << 31)

Do not write any audio to this channel until the state is up.

Definition at line 757 of file app_meetme.c.

◆ CONFIG_FILE_NAME

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 655 of file app_meetme.c.

◆ DATE_FORMAT

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

String format for scheduled conferences

Definition at line 662 of file app_meetme.c.

◆ DEFAULT_AUDIO_BUFFERS

#define DEFAULT_AUDIO_BUFFERS   32

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

Definition at line 659 of file app_meetme.c.

◆ MAX_CONFNUM

#define MAX_CONFNUM   80

Definition at line 827 of file app_meetme.c.

◆ MAX_PIN

#define MAX_PIN   80

Definition at line 828 of file app_meetme.c.

◆ MAX_SETTINGS

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

Definition at line 832 of file app_meetme.c.

◆ MC_DATA_FORMAT

#define MC_DATA_FORMAT   "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"

◆ MC_HEADER_FORMAT

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

◆ MEETME_DELAYDETECTENDTALK

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 674 of file app_meetme.c.

◆ MEETME_DELAYDETECTTALK

#define MEETME_DELAYDETECTTALK   300

Definition at line 673 of file app_meetme.c.

◆ OPTIONS_LEN

#define OPTIONS_LEN   100

Definition at line 829 of file app_meetme.c.

◆ STR_CONCISE

#define STR_CONCISE   "concise"

Definition at line 656 of file app_meetme.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
ADMINFLAG_MUTED 

User is muted

ADMINFLAG_SELFMUTED 

User muted self

ADMINFLAG_KICKME 

User has been kicked

ADMINFLAG_T_REQUEST 

User has requested to speak

ADMINFLAG_HANGUP 

User will be leaving the conference

Definition at line 664 of file app_meetme.c.

664 {
665 ADMINFLAG_MUTED = (1 << 1), /*!< User is muted */
666 ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
667 ADMINFLAG_KICKME = (1 << 3), /*!< User has been kicked */
668 /*! User has requested to speak */
669 ADMINFLAG_T_REQUEST = (1 << 4),
670 ADMINFLAG_HANGUP = (1 << 5), /*!< User will be leaving the conference */
671};
@ ADMINFLAG_SELFMUTED
Definition: app_meetme.c:666
@ ADMINFLAG_KICKME
Definition: app_meetme.c:667
@ ADMINFLAG_MUTED
Definition: app_meetme.c:665
@ ADMINFLAG_HANGUP
Definition: app_meetme.c:670
@ ADMINFLAG_T_REQUEST
Definition: app_meetme.c:669

◆ anonymous enum

anonymous enum
Enumerator
CONFFLAG_ADMIN 

user has admin access on the conference

CONFFLAG_MONITOR 

If set the user can only receive audio from the conference

CONFFLAG_KEYEXIT 

If set asterisk will exit conference when key defined in p() option is pressed

CONFFLAG_STARMENU 

If set asterisk will provide a menu to the user when '*' is pressed

CONFFLAG_TALKER 

If set the use can only send audio to the conference

CONFFLAG_QUIET 

If set there will be no enter or leave sounds

CONFFLAG_ANNOUNCEUSERCOUNT 

If set, when user joins the conference, they will be told the number of users that are already in

CONFFLAG_AGI 

Set to run AGI Script in Background

CONFFLAG_MOH 

Set to have music on hold when user is alone in conference

CONFFLAG_MARKEDEXIT 

If set, the channel will leave the conference if all marked users leave

CONFFLAG_WAITMARKED 

If set, the MeetMe will wait until a marked user enters

CONFFLAG_EXIT_CONTEXT 

If set, the MeetMe will exit to the specified context

CONFFLAG_MARKEDUSER 

If set, the user will be marked

CONFFLAG_INTROUSER 

If set, user will be ask record name on entry of conference

CONFFLAG_RECORDCONF 

If set, the MeetMe will be recorded

CONFFLAG_MONITORTALKER 

If set, the user will be monitored if the user is talking or not

CONFFLAG_DYNAMIC 
CONFFLAG_DYNAMICPIN 
CONFFLAG_EMPTY 
CONFFLAG_EMPTYNOPIN 
CONFFLAG_ALWAYSPROMPT 
CONFFLAG_OPTIMIZETALKER 

If set, treat talking users as muted users

CONFFLAG_NOONLYPERSON 

If set, won't speak the extra prompt when the first person enters the conference

CONFFLAG_INTROUSERNOREVIEW 

If set, user will be asked to record name on entry of conference without review

CONFFLAG_STARTMUTED 

If set, the user will be initially self-muted

CONFFLAG_PASS_DTMF 

Pass DTMF through the conference

CONFFLAG_KICK_CONTINUE 

If set, the user should continue in the dialplan if kicked out

CONFFLAG_DURATION_STOP 
CONFFLAG_DURATION_LIMIT 

Definition at line 697 of file app_meetme.c.

697 {
698 /*! user has admin access on the conference */
699 CONFFLAG_ADMIN = (1 << 0),
700 /*! If set the user can only receive audio from the conference */
701 CONFFLAG_MONITOR = (1 << 1),
702 /*! If set asterisk will exit conference when key defined in p() option is pressed */
703 CONFFLAG_KEYEXIT = (1 << 2),
704 /*! If set asterisk will provide a menu to the user when '*' is pressed */
705 CONFFLAG_STARMENU = (1 << 3),
706 /*! If set the use can only send audio to the conference */
707 CONFFLAG_TALKER = (1 << 4),
708 /*! If set there will be no enter or leave sounds */
709 CONFFLAG_QUIET = (1 << 5),
710 /*! If set, when user joins the conference, they will be told the number
711 * of users that are already in */
713 /*! Set to run AGI Script in Background */
714 CONFFLAG_AGI = (1 << 7),
715 /*! Set to have music on hold when user is alone in conference */
716 CONFFLAG_MOH = (1 << 8),
717 /*! If set, the channel will leave the conference if all marked users leave */
718 CONFFLAG_MARKEDEXIT = (1 << 9),
719 /*! If set, the MeetMe will wait until a marked user enters */
720 CONFFLAG_WAITMARKED = (1 << 10),
721 /*! If set, the MeetMe will exit to the specified context */
722 CONFFLAG_EXIT_CONTEXT = (1 << 11),
723 /*! If set, the user will be marked */
724 CONFFLAG_MARKEDUSER = (1 << 12),
725 /*! If set, user will be ask record name on entry of conference */
726 CONFFLAG_INTROUSER = (1 << 13),
727 /*! If set, the MeetMe will be recorded */
728 CONFFLAG_RECORDCONF = (1<< 14),
729 /*! If set, the user will be monitored if the user is talking or not */
730 CONFFLAG_MONITORTALKER = (1 << 15),
731 CONFFLAG_DYNAMIC = (1 << 16),
732 CONFFLAG_DYNAMICPIN = (1 << 17),
733 CONFFLAG_EMPTY = (1 << 18),
734 CONFFLAG_EMPTYNOPIN = (1 << 19),
735 CONFFLAG_ALWAYSPROMPT = (1 << 20),
736 /*! If set, treat talking users as muted users */
737 CONFFLAG_OPTIMIZETALKER = (1 << 21),
738 /*! If set, won't speak the extra prompt when the first person
739 * enters the conference */
740 CONFFLAG_NOONLYPERSON = (1 << 22),
741 /*! If set, user will be asked to record name on entry of conference
742 * without review */
743 CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
744 /*! If set, the user will be initially self-muted */
745 CONFFLAG_STARTMUTED = (1 << 24),
746 /*! Pass DTMF through the conference */
747 CONFFLAG_PASS_DTMF = (1 << 25),
748 /*! If set, the user should continue in the dialplan if kicked out */
749 CONFFLAG_KICK_CONTINUE = (1 << 26),
750 CONFFLAG_DURATION_STOP = (1 << 27),
751 CONFFLAG_DURATION_LIMIT = (1 << 28),
752};
@ CONFFLAG_INTROUSERNOREVIEW
Definition: app_meetme.c:743
@ CONFFLAG_QUIET
Definition: app_meetme.c:709
@ CONFFLAG_INTROUSER
Definition: app_meetme.c:726
@ CONFFLAG_TALKER
Definition: app_meetme.c:707
@ CONFFLAG_ALWAYSPROMPT
Definition: app_meetme.c:735
@ CONFFLAG_OPTIMIZETALKER
Definition: app_meetme.c:737
@ CONFFLAG_MARKEDUSER
Definition: app_meetme.c:724
@ CONFFLAG_MARKEDEXIT
Definition: app_meetme.c:718
@ CONFFLAG_EXIT_CONTEXT
Definition: app_meetme.c:722
@ CONFFLAG_ANNOUNCEUSERCOUNT
Definition: app_meetme.c:712
@ CONFFLAG_DURATION_LIMIT
Definition: app_meetme.c:751
@ CONFFLAG_WAITMARKED
Definition: app_meetme.c:720
@ CONFFLAG_PASS_DTMF
Definition: app_meetme.c:747
@ CONFFLAG_EMPTY
Definition: app_meetme.c:733
@ CONFFLAG_DYNAMICPIN
Definition: app_meetme.c:732
@ CONFFLAG_DURATION_STOP
Definition: app_meetme.c:750
@ CONFFLAG_STARMENU
Definition: app_meetme.c:705
@ CONFFLAG_MOH
Definition: app_meetme.c:716
@ CONFFLAG_KICK_CONTINUE
Definition: app_meetme.c:749
@ CONFFLAG_AGI
Definition: app_meetme.c:714
@ CONFFLAG_RECORDCONF
Definition: app_meetme.c:728
@ CONFFLAG_MONITORTALKER
Definition: app_meetme.c:730
@ CONFFLAG_MONITOR
Definition: app_meetme.c:701
@ CONFFLAG_NOONLYPERSON
Definition: app_meetme.c:740
@ CONFFLAG_STARTMUTED
Definition: app_meetme.c:745
@ CONFFLAG_EMPTYNOPIN
Definition: app_meetme.c:734
@ CONFFLAG_DYNAMIC
Definition: app_meetme.c:731
@ CONFFLAG_KEYEXIT
Definition: app_meetme.c:703
@ CONFFLAG_ADMIN
Definition: app_meetme.c:699

◆ anonymous enum

anonymous enum
Enumerator
OPT_ARG_WAITMARKED 
OPT_ARG_EXITKEYS 
OPT_ARG_DURATION_STOP 
OPT_ARG_DURATION_LIMIT 
OPT_ARG_MOH_CLASS 
OPT_ARG_INTROMSG 
OPT_ARG_INTROUSER_VMREC 
OPT_ARG_ARRAY_SIZE 

Definition at line 765 of file app_meetme.c.

765 {
774};
@ OPT_ARG_MOH_CLASS
Definition: app_meetme.c:770
@ OPT_ARG_DURATION_STOP
Definition: app_meetme.c:768
@ OPT_ARG_EXITKEYS
Definition: app_meetme.c:767
@ OPT_ARG_INTROMSG
Definition: app_meetme.c:771
@ OPT_ARG_DURATION_LIMIT
Definition: app_meetme.c:769
@ OPT_ARG_WAITMARKED
Definition: app_meetme.c:766
@ OPT_ARG_ARRAY_SIZE
Definition: app_meetme.c:773
@ OPT_ARG_INTROUSER_VMREC
Definition: app_meetme.c:772

◆ announcetypes

Enumerator
CONF_HASJOIN 
CONF_HASLEFT 

Definition at line 834 of file app_meetme.c.

834 {
837};
@ CONF_HASJOIN
Definition: app_meetme.c:835
@ CONF_HASLEFT
Definition: app_meetme.c:836

◆ entrance_sound

Enumerator
ENTER 
LEAVE 

Definition at line 683 of file app_meetme.c.

683 {
684 ENTER,
685 LEAVE
686};
@ ENTER
Definition: app_meetme.c:684
@ LEAVE
Definition: app_meetme.c:685

◆ menu_modes

enum menu_modes
Enumerator
MENU_DISABLED 
MENU_NORMAL 
MENU_ADMIN 
MENU_ADMIN_EXTENDED 

Definition at line 2310 of file app_meetme.c.

2310 {
2311 MENU_DISABLED = 0,
2313 MENU_ADMIN,
2315};
@ MENU_ADMIN
Definition: app_meetme.c:2313
@ MENU_ADMIN_EXTENDED
Definition: app_meetme.c:2314
@ MENU_DISABLED
Definition: app_meetme.c:2311
@ MENU_NORMAL
Definition: app_meetme.c:2312

◆ recording_state

Enumerator
MEETME_RECORD_OFF 
MEETME_RECORD_STARTED 
MEETME_RECORD_ACTIVE 
MEETME_RECORD_TERMINATE 

Definition at line 688 of file app_meetme.c.

688 {
693};
@ MEETME_RECORD_STARTED
Definition: app_meetme.c:690
@ MEETME_RECORD_OFF
Definition: app_meetme.c:689
@ MEETME_RECORD_TERMINATE
Definition: app_meetme.c:692
@ MEETME_RECORD_ACTIVE
Definition: app_meetme.c:691

◆ volume_action

Enumerator
VOL_UP 
VOL_DOWN 

Definition at line 678 of file app_meetme.c.

678 {
679 VOL_UP,
681};
@ VOL_UP
Definition: app_meetme.c:679
@ VOL_DOWN
Definition: app_meetme.c:680

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 5566 of file app_meetme.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 5566 of file app_meetme.c.

◆ acf_meetme_info()

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

Definition at line 5432 of file app_meetme.c.

5433{
5434 struct ast_conference *conf;
5435 char *parse;
5436 int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
5438 AST_APP_ARG(keyword);
5440 );
5441
5442 if (ast_strlen_zero(data)) {
5443 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
5444 return -1;
5445 }
5446
5447 parse = ast_strdupa(data);
5449
5450 if (ast_strlen_zero(args.keyword)) {
5451 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
5452 return -1;
5453 }
5454
5455 if (ast_strlen_zero(args.confno)) {
5456 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
5457 return -1;
5458 }
5459
5462 if (!strcmp(args.confno, conf->confno)) {
5464 break;
5465 }
5466 }
5468
5469 if (result > -1) {
5470 snprintf(buf, len, "%d", result);
5471 } else if (result == -1) {
5472 ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
5473 snprintf(buf, len, "0");
5474 } else if (result == -2) {
5475 ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
5476 snprintf(buf, len, "0");
5477 }
5478
5479 return 0;
5480}
static int acf_meetme_info_eval(const char *keyword, const struct ast_conference *conf)
Definition: app_meetme.c:5414
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
static PGresult * result
Definition: cel_pgsql.c:84
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define LOG_ERROR
#define LOG_NOTICE
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
The MeetMe Conference object.
Definition: app_meetme.c:850
char confno[MAX_CONFNUM]
Definition: app_meetme.c:853
struct ast_conference::@34 list
All configuration options for http media cache.
const char * args

References acf_meetme_info_eval(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), buf, ast_conference::confno, len(), ast_conference::list, LOG_ERROR, LOG_NOTICE, and result.

◆ acf_meetme_info_eval()

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

Definition at line 5414 of file app_meetme.c.

5415{
5416 if (!strcasecmp("lock", keyword)) {
5417 return conf->locked;
5418 } else if (!strcasecmp("parties", keyword)) {
5419 return conf->users;
5420 } else if (!strcasecmp("activity", keyword)) {
5421 time_t now;
5422 now = time(NULL);
5423 return (now - conf->start);
5424 } else if (!strcasecmp("dynamic", keyword)) {
5425 return conf->isdynamic;
5426 } else {
5427 return -1;
5428 }
5429
5430}
#define NULL
Definition: resample.c:96

References NULL.

Referenced by acf_meetme_info().

◆ action_meetmelist()

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

Definition at line 5081 of file app_meetme.c.

5082{
5083 const char *actionid = astman_get_header(m, "ActionID");
5084 const char *conference = astman_get_header(m, "Conference");
5085 char idText[80] = "";
5086 struct ast_conference *cnf;
5087 struct ast_conf_user *user;
5088 struct ao2_iterator user_iter;
5089 int total = 0;
5090
5091 if (!ast_strlen_zero(actionid))
5092 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5093
5094 if (AST_LIST_EMPTY(&confs)) {
5095 astman_send_error(s, m, "No active conferences.");
5096 return 0;
5097 }
5098
5099 astman_send_listack(s, m, "Meetme user list will follow", "start");
5100
5101 /* Find the right conference */
5103 AST_LIST_TRAVERSE(&confs, cnf, list) {
5104 /* If we ask for one particular, and this isn't it, skip it */
5105 if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
5106 continue;
5107
5108 /* Show all the users */
5109 user_iter = ao2_iterator_init(cnf->usercontainer, 0);
5110 while ((user = ao2_iterator_next(&user_iter))) {
5111 total++;
5112 astman_append(s,
5113 "Event: MeetmeList\r\n"
5114 "%s"
5115 "Conference: %s\r\n"
5116 "UserNumber: %d\r\n"
5117 "CallerIDNum: %s\r\n"
5118 "CallerIDName: %s\r\n"
5119 "ConnectedLineNum: %s\r\n"
5120 "ConnectedLineName: %s\r\n"
5121 "Channel: %s\r\n"
5122 "Admin: %s\r\n"
5123 "Role: %s\r\n"
5124 "MarkedUser: %s\r\n"
5125 "Muted: %s\r\n"
5126 "Talking: %s\r\n"
5127 "\r\n",
5128 idText,
5129 cnf->confno,
5130 user->user_no,
5132 S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
5135 ast_channel_name(user->chan),
5136 ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
5137 ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
5138 ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
5139 user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
5140 user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
5141 ao2_ref(user, -1);
5142 }
5143 ao2_iterator_destroy(&user_iter);
5144 }
5146
5147 /* Send final confirmation */
5148 astman_send_list_complete_start(s, m, "MeetmeListComplete", total);
5150 return 0;
5151}
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
const char * ast_channel_name(const struct ast_channel *chan)
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3431
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3389
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3467
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3050
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3475
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3310
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
static int total
Definition: res_adsi.c:970
static char user[512]
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
The MeetMe User object.
Definition: app_meetme.c:904
struct ao2_container * usercontainer
Definition: app_meetme.c:883
struct ast_party_id id
Caller party ID.
Definition: channel.h:420
struct ast_party_id id
Connected party ID.
Definition: channel.h:458
struct ast_party_name name
Subscriber name.
Definition: channel.h:340
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:279
char * str
Subscriber name (Malloced)
Definition: channel.h:264
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:297
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291
structure to hold users read from users.conf
#define ast_test_flag64(p, flag)
Definition: utils.h:120

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_caller(), ast_channel_connected(), ast_channel_name(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_test_flag64, astman_append(), astman_get_header(), astman_send_error(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), CONFFLAG_ADMIN, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_TALKER, ast_conference::confno, ast_party_caller::id, ast_party_connected_line::id, ast_party_id::name, ast_party_id::number, S_COR, ast_party_name::str, ast_party_number::str, total, user, ast_conference::usercontainer, ast_party_name::valid, and ast_party_number::valid.

Referenced by load_module().

◆ action_meetmelistrooms()

static int action_meetmelistrooms ( struct mansession s,
const struct message m 
)
static

Definition at line 5153 of file app_meetme.c.

5154{
5155 const char *actionid = astman_get_header(m, "ActionID");
5156 char idText[80] = "";
5157 struct ast_conference *cnf;
5158 int totalitems = 0;
5159 int hr, min, sec;
5160 time_t now;
5161 char markedusers[5];
5162
5163 if (!ast_strlen_zero(actionid)) {
5164 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5165 }
5166
5167 if (AST_LIST_EMPTY(&confs)) {
5168 astman_send_error(s, m, "No active conferences.");
5169 return 0;
5170 }
5171
5172 astman_send_listack(s, m, "Meetme conferences will follow", "start");
5173
5174 now = time(NULL);
5175
5176 /* Traverse the conference list */
5178 AST_LIST_TRAVERSE(&confs, cnf, list) {
5179 totalitems++;
5180
5181 if (cnf->markedusers == 0) {
5182 strcpy(markedusers, "N/A");
5183 } else {
5184 sprintf(markedusers, "%.4d", cnf->markedusers);
5185 }
5186 hr = (now - cnf->start) / 3600;
5187 min = ((now - cnf->start) % 3600) / 60;
5188 sec = (now - cnf->start) % 60;
5189
5190 astman_append(s,
5191 "Event: MeetmeListRooms\r\n"
5192 "%s"
5193 "Conference: %s\r\n"
5194 "Parties: %d\r\n"
5195 "Marked: %s\r\n"
5196 "Activity: %2.2d:%2.2d:%2.2d\r\n"
5197 "Creation: %s\r\n"
5198 "Locked: %s\r\n"
5199 "\r\n",
5200 idText,
5201 cnf->confno,
5202 cnf->users,
5204 hr, min, sec,
5205 cnf->isdynamic ? "Dynamic" : "Static",
5206 cnf->locked ? "Yes" : "No");
5207 }
5209
5210 /* Send final confirmation */
5211 astman_send_list_complete_start(s, m, "MeetmeListRoomsComplete", totalitems);
5213 return 0;
5214}
#define min(a, b)
Definition: f2c.h:197
unsigned int isdynamic
Definition: app_meetme.c:865
unsigned int locked
Definition: app_meetme.c:866

References AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_error(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_conference::confno, ast_conference::isdynamic, ast_conference::list, ast_conference::locked, ast_conference::markedusers, min, NULL, ast_conference::start, and ast_conference::users.

Referenced by load_module().

◆ action_meetmemute()

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

Definition at line 5071 of file app_meetme.c.

5072{
5073 return meetmemute(s, m, 1);
5074}
static int meetmemute(struct mansession *s, const struct message *m, int mute)
Definition: app_meetme.c:5011

References meetmemute().

Referenced by load_module().

◆ action_meetmeunmute()

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

Definition at line 5076 of file app_meetme.c.

5077{
5078 return meetmemute(s, m, 0);
5079}

References meetmemute().

Referenced by load_module().

◆ admin_exec()

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

The MeetMeAdmin application.

MeetMeAdmin(confno, command, caller)

Definition at line 4777 of file app_meetme.c.

4777 {
4778 char *params;
4779 struct ast_conference *cnf;
4780 struct ast_conf_user *user = NULL;
4782 AST_APP_ARG(confno);
4783 AST_APP_ARG(command);
4785 );
4786 int res = 0;
4787
4788 if (ast_strlen_zero(data)) {
4789 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
4790 if (chan) {
4791 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
4792 }
4793 return -1;
4794 }
4795
4796 params = ast_strdupa(data);
4797 AST_STANDARD_APP_ARGS(args, params);
4798
4799 if (!args.command) {
4800 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
4801 if (chan) {
4802 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
4803 }
4804 return -1;
4805 }
4806
4808 AST_LIST_TRAVERSE(&confs, cnf, list) {
4809 if (!strcmp(cnf->confno, args.confno))
4810 break;
4811 }
4812
4813 if (!cnf) {
4814 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
4816 if (chan) {
4817 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
4818 }
4819 return 0;
4820 }
4821
4823
4824 if (args.user) {
4825 user = find_user(cnf, args.user);
4826 if (!user) {
4827 ast_log(LOG_NOTICE, "Specified User not found!\n");
4828 res = -2;
4829 goto usernotfound;
4830 }
4831 } else {
4832 /* fail for commands that require a user */
4833 switch (*args.command) {
4834 case 'm': /* Unmute */
4835 case 'M': /* Mute */
4836 case 't': /* Lower user's talk volume */
4837 case 'T': /* Raise user's talk volume */
4838 case 'u': /* Lower user's listen volume */
4839 case 'U': /* Raise user's listen volume */
4840 case 'r': /* Reset user's volume level */
4841 case 'k': /* Kick user */
4842 res = -2;
4843 ast_log(LOG_NOTICE, "No user specified!\n");
4844 goto usernotfound;
4845 default:
4846 break;
4847 }
4848 }
4849
4850 switch (*args.command) {
4851 case 76: /* L: Lock */
4852 cnf->locked = 1;
4853 break;
4854 case 108: /* l: Unlock */
4855 cnf->locked = 0;
4856 break;
4857 case 75: /* K: kick all users */
4859 break;
4860 case 101: /* e: Eject last user*/
4861 {
4862 int max_no = 0;
4863 RAII_VAR(struct ast_conf_user *, eject_user, NULL, ao2_cleanup);
4864
4866 eject_user = ao2_find(cnf->usercontainer, &max_no, 0);
4867 if (!eject_user) {
4868 res = -1;
4869 ast_log(LOG_NOTICE, "No last user to kick!\n");
4870 break;
4871 }
4872
4873 if (!ast_test_flag64(&eject_user->userflags, CONFFLAG_ADMIN)) {
4874 eject_user->adminflags |= ADMINFLAG_KICKME;
4875 } else {
4876 res = -1;
4877 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
4878 }
4879 break;
4880 }
4881 case 77: /* M: Mute */
4882 user->adminflags |= ADMINFLAG_MUTED;
4883 break;
4884 case 78: /* N: Mute all (non-admin) users */
4886 break;
4887 case 109: /* m: Unmute */
4889 break;
4890 case 110: /* n: Unmute all users */
4892 break;
4893 case 107: /* k: Kick user */
4894 user->adminflags |= ADMINFLAG_KICKME;
4895 break;
4896 case 118: /* v: Lower all users listen volume */
4898 break;
4899 case 86: /* V: Raise all users listen volume */
4901 break;
4902 case 115: /* s: Lower all users speaking volume */
4904 break;
4905 case 83: /* S: Raise all users speaking volume */
4907 break;
4908 case 82: /* R: Reset all volume levels */
4910 break;
4911 case 114: /* r: Reset user's volume level */
4913 break;
4914 case 85: /* U: Raise user's listen volume */
4916 break;
4917 case 117: /* u: Lower user's listen volume */
4919 break;
4920 case 84: /* T: Raise user's talk volume */
4922 break;
4923 case 116: /* t: Lower user's talk volume */
4925 break;
4926 case 'E': /* E: Extend conference */
4927 if (rt_extend_conf(args.confno)) {
4928 res = -1;
4929 }
4930 break;
4931 }
4932
4933 if (args.user) {
4934 /* decrement reference from find_user */
4935 ao2_ref(user, -1);
4936 }
4937usernotfound:
4939
4940 dispose_conf(cnf);
4941 if (chan) {
4942 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
4943 }
4944
4945 return 0;
4946}
static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
Definition: app_meetme.c:1328
static int user_set_kickme_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2277
static int dispose_conf(struct ast_conference *conf)
Decrement reference counts, as incremented by find_conf()
Definition: app_meetme.c:2065
static int user_max_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:1401
static int rt_extend_conf(const char *confno)
Definition: app_meetme.c:2084
static int user_reset_vol_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:4755
static void reset_volumes(struct ast_conf_user *user)
Definition: app_meetme.c:1340
static struct ast_conf_user * find_user(struct ast_conference *conf, const char *callerident)
Definition: app_meetme.c:4714
static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2299
static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
Definition: app_meetme.c:1316
static int user_set_unmuted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2288
static int user_talk_voldown_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:4748
static int user_listen_volup_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:4727
static int user_listen_voldown_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:4734
static int user_talk_volup_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:4741
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
@ OBJ_NODATA
Definition: astobj2.h:1044
#define LOG_WARNING
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
struct ast_channel * chan
Definition: app_meetme.c:908
struct ast_conf_user::@36 list
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ao2_callback, ao2_cleanup, ao2_find, ao2_ref, args, AST_APP_ARG, ast_atomic_fetchadd_int(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag64, ast_conf_user::chan, CONFFLAG_ADMIN, ast_conference::confno, dispose_conf(), find_user(), ast_conf_user::list, ast_conference::locked, LOG_NOTICE, LOG_WARNING, NULL, OBJ_NODATA, pbx_builtin_setvar_helper(), RAII_VAR, ast_conference::refcount, reset_volumes(), rt_extend_conf(), tweak_listen_volume(), tweak_talk_volume(), user_listen_voldown_cb(), user_listen_volup_cb(), user_max_cmp(), user_reset_vol_cb(), user_set_kickme_cb(), user_set_muted_cb(), user_set_unmuted_cb(), user_talk_voldown_cb(), user_talk_volup_cb(), ast_conference::usercontainer, VOL_DOWN, and VOL_UP.

Referenced by load_module(), and meetme_cmd_helper().

◆ announce_thread()

static void * announce_thread ( void *  data)
static

Definition at line 2176 of file app_meetme.c.

2177{
2178 struct announce_listitem *current;
2179 struct ast_conference *conf = data;
2180 int res;
2181 char filename[PATH_MAX] = "";
2183 AST_LIST_HEAD_INIT_NOLOCK(&local_list);
2184
2185 while (!conf->announcethread_stop) {
2186 ast_mutex_lock(&conf->announcelistlock);
2187 if (conf->announcethread_stop) {
2188 ast_mutex_unlock(&conf->announcelistlock);
2189 break;
2190 }
2191 if (AST_LIST_EMPTY(&conf->announcelist))
2192 ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
2193
2194 AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
2195 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
2196
2197 ast_mutex_unlock(&conf->announcelistlock);
2198 if (conf->announcethread_stop) {
2199 break;
2200 }
2201
2202 for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
2203 ast_debug(1, "About to play %s\n", current->namerecloc);
2204 if (!ast_fileexists(current->namerecloc, NULL, NULL))
2205 continue;
2206 if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
2207 if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
2208 res = ast_waitstream(current->confchan, "");
2209 if (!res) {
2210 ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
2211 if (!ast_streamfile(current->confchan, filename, current->language))
2212 ast_waitstream(current->confchan, "");
2213 }
2214 }
2215 if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
2216 /* only remove it if it isn't a VM recording file */
2217 ast_filedelete(current->namerecloc, NULL);
2218 }
2219 }
2220 }
2221
2222 /* thread marked to stop, clean up */
2223 while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
2224 /* only delete if it's a vm rec */
2225 if (!current->vmrec) {
2226 ast_filedelete(current->namerecloc, NULL);
2227 }
2228 ao2_ref(current, -1);
2229 }
2230 return NULL;
2231}
static const char * get_announce_filename(enum announcetypes type)
Definition: app_meetme.c:2162
#define PATH_MAX
Definition: asterisk.h:40
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1293
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1129
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1141
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1840
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:783
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
size_t current
Definition: main/cli.c:113
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Definition: search.h:40

References ao2_ref, ast_check_hangup(), ast_cond_wait, ast_copy_string(), ast_debug, 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_mutex_lock, ast_mutex_unlock, ast_streamfile(), ast_waitstream(), CONF_HASLEFT, current, get_announce_filename(), NULL, and PATH_MAX.

Referenced by conf_run().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 5566 of file app_meetme.c.

◆ build_conf()

static struct ast_conference * build_conf ( const char *  confno,
const char *  pin,
const char *  pinadmin,
int  make,
int  dynamic,
int  refcount,
const struct ast_channel chan,
struct ast_test *  test 
)
static

Find or create a conference.

Parameters
confnoThe conference name/number
pinThe regular user pin
pinadminThe admin pin
makeMake the conf if it doesn't exist
dynamicMark the newly created conference as dynamic
refcountHow many references to mark on the conference
chanThe asterisk channel
test
Returns
A pointer to the conference struct, or NULL if it wasn't found and make or dynamic were not set.

Definition at line 1428 of file app_meetme.c.

1431{
1432 struct ast_conference *cnf;
1433 struct dahdi_confinfo dahdic = { 0, };
1434 int confno_int = 0;
1436
1438
1439 AST_LIST_TRAVERSE(&confs, cnf, list) {
1440 if (!strcmp(confno, cnf->confno))
1441 break;
1442 }
1443
1444 if (cnf || (!make && !dynamic) || !cap_slin)
1445 goto cnfout;
1446
1448 /* Make a new one */
1449 cnf = ast_calloc(1, sizeof(*cnf));
1450 if (!cnf) {
1451 goto cnfout;
1452 }
1453
1455 NULL, user_no_cmp);
1456 if (!cnf->usercontainer) {
1457 goto cnfout;
1458 }
1459
1460 ast_mutex_init(&cnf->playlock);
1466 ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
1467 ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
1468 ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
1469 ast_copy_string(cnf->uniqueid, ast_channel_uniqueid(chan), sizeof(cnf->uniqueid));
1470
1471 /* Setup a new dahdi conference */
1472 dahdic.confno = -1;
1473 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1474 cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
1475 if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
1476 if (test) {
1477 /* if we are creating a conference for a unit test, it is not neccesary
1478 * to open a pseudo channel, so, if we fail continue creating
1479 * the conference. */
1480 ast_test_status_update(test, "Unable to open DAHDI pseudo device\n");
1481 } else {
1482 ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
1483 if (cnf->fd >= 0)
1484 close(cnf->fd);
1485 ao2_ref(cnf->usercontainer, -1);
1490 ast_free(cnf);
1491 cnf = NULL;
1492 goto cnfout;
1493 }
1494 }
1495
1496 cnf->dahdiconf = dahdic.confno;
1497
1498 /* Setup a new channel for playback of audio files */
1499 cnf->chan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL);
1500 if (cnf->chan) {
1503 dahdic.chan = 0;
1504 dahdic.confno = cnf->dahdiconf;
1505 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1506 if (ioctl(ast_channel_fd(cnf->chan, 0), DAHDI_SETCONF, &dahdic)) {
1507 if (test) {
1508 ast_test_status_update(test, "Error setting conference on pseudo channel\n");
1509 }
1510 ast_log(LOG_WARNING, "Error setting conference\n");
1511 if (cnf->chan)
1512 ast_hangup(cnf->chan);
1513 else
1514 close(cnf->fd);
1515 ao2_ref(cnf->usercontainer, -1);
1520 ast_free(cnf);
1521 cnf = NULL;
1522 goto cnfout;
1523 }
1524 }
1525
1526 /* Fill the conference struct */
1527 cnf->start = time(NULL);
1528 cnf->maxusers = 0x7fffffff;
1529 cnf->isdynamic = dynamic ? 1 : 0;
1530 ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
1531 AST_LIST_INSERT_HEAD(&confs, cnf, list);
1532
1533 /* Reserve conference number in map */
1534 if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
1535 conf_map[confno_int] = 1;
1536
1537cnfout:
1538 ao2_cleanup(cap_slin);
1539 if (cnf)
1540 ast_atomic_fetchadd_int(&cnf->refcount, refcount);
1541
1543
1544 return cnf;
1545}
static int user_no_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:1389
static unsigned int conf_map[1024]
Definition: app_meetme.c:896
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int ast_channel_fd(const struct ast_channel *chan, int which)
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5762
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5803
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6354
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
#define ast_verb(level,...)
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_destroy(a)
Definition: lock.h:188
ast_mutex_t announcethreadlock
Definition: app_meetme.c:887
pthread_t announcethread
Definition: app_meetme.c:886
ast_mutex_t recordthreadlock
Definition: app_meetme.c:869
char pinadmin[MAX_PIN]
Definition: app_meetme.c:874
ast_mutex_t playlock
Definition: app_meetme.c:851
struct ast_channel * chan
Definition: app_meetme.c:854
pthread_t recordthread
Definition: app_meetme.c:868
char pin[MAX_PIN]
Definition: app_meetme.c:873
char uniqueid[32]
Definition: app_meetme.c:875
ast_mutex_t listenlock
Definition: app_meetme.c:852
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
#define ast_test_status_update(a, b, c...)
Definition: test.h:129

References ast_conference::announcethread, ast_conference::announcethreadlock, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_cleanup, ao2_container_alloc_list, ao2_ref, ast_atomic_fetchadd_int(), ast_calloc, ast_channel_fd(), ast_channel_uniqueid(), ast_copy_string(), ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_slin, ast_free, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_mutex_destroy, ast_mutex_init, AST_PTHREADT_NULL, ast_request(), ast_set_read_format(), ast_set_write_format(), ast_test_status_update, ast_verb, ast_conference::chan, conf_map, ast_conference::confno, ast_conference::dahdiconf, ast_conference::fd, ast_conference::isdynamic, ast_conference::listenlock, LOG_WARNING, ast_conference::maxusers, NULL, ast_conference::pin, ast_conference::pinadmin, ast_conference::playlock, ast_conference::recordthread, ast_conference::recordthreadlock, ast_conference::refcount, ast_conference::start, ast_conference::uniqueid, user_no_cmp(), and ast_conference::usercontainer.

Referenced by find_conf(), and find_conf_realtime().

◆ can_write()

static int can_write ( struct ast_channel chan,
struct ast_flags64 confflags 
)
static

Definition at line 2233 of file app_meetme.c.

2234{
2236 return 1;
2237 }
2238
2239 return (ast_channel_state(chan) == AST_STATE_UP);
2240}
#define CONFFLAG_NO_AUDIO_UNTIL_UP
Definition: app_meetme.c:757
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42

References AST_STATE_UP, ast_test_flag64, ast_conference::chan, and CONFFLAG_NO_AUDIO_UNTIL_UP.

Referenced by conf_run().

◆ careful_write()

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

Definition at line 1230 of file app_meetme.c.

1231{
1232 int res;
1233 int x;
1234
1235 while (len) {
1236 if (block) {
1237 x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
1238 res = ioctl(fd, DAHDI_IOMUX, &x);
1239 } else
1240 res = 0;
1241 if (res >= 0)
1242 res = write(fd, data, len);
1243 if (res < 1) {
1244 if (errno != EAGAIN) {
1245 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
1246 return -1;
1247 } else
1248 return 0;
1249 }
1250 len -= res;
1251 data += res;
1252 }
1253
1254 return 0;
1255}
int errno

References ast_log, errno, len(), and LOG_WARNING.

Referenced by conf_play(), and conf_run().

◆ channel_admin_exec()

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

The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command)

Definition at line 4950 of file app_meetme.c.

4950 {
4951 char *params;
4952 struct ast_conference *conf = NULL;
4953 struct ast_conf_user *user = NULL;
4955 AST_APP_ARG(channel);
4956 AST_APP_ARG(command);
4957 );
4958
4959 if (ast_strlen_zero(data)) {
4960 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
4961 return -1;
4962 }
4963
4964 params = ast_strdupa(data);
4965 AST_STANDARD_APP_ARGS(args, params);
4966
4967 if (!args.channel) {
4968 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
4969 return -1;
4970 }
4971
4972 if (!args.command) {
4973 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
4974 return -1;
4975 }
4976
4979 if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
4980 break;
4981 }
4982 }
4983
4984 if (!user) {
4985 ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
4987 return 0;
4988 }
4989
4990 /* perform the specified action */
4991 switch (*args.command) {
4992 case 77: /* M: Mute */
4993 user->adminflags |= ADMINFLAG_MUTED;
4994 break;
4995 case 109: /* m: Unmute */
4996 user->adminflags &= ~ADMINFLAG_MUTED;
4997 break;
4998 case 107: /* k: Kick user */
4999 user->adminflags |= ADMINFLAG_KICKME;
5000 break;
5001 default: /* unknown command */
5002 ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
5003 break;
5004 }
5005 ao2_ref(user, -1);
5007
5008 return 0;
5009}
static int user_chan_cb(void *obj, void *args, int flags)
Definition: app_meetme.c:4762

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ao2_callback, ao2_ref, args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_conf_user::list, LOG_NOTICE, LOG_WARNING, NULL, and user_chan_cb().

Referenced by load_module().

◆ complete_confno()

static char * complete_confno ( const char *  word,
int  state 
)
static

Definition at line 1547 of file app_meetme.c.

1548{
1549 struct ast_conference *cnf;
1550 char *ret = NULL;
1551 int which = 0;
1552 int len = strlen(word);
1553
1555 AST_LIST_TRAVERSE(&confs, cnf, list) {
1556 if (!strncmp(word, cnf->confno, len) && ++which > state) {
1557 /* dup before releasing the lock */
1558 ret = ast_strdup(cnf->confno);
1559 break;
1560 }
1561 }
1563 return ret;
1564}
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
short word

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_conference::confno, len(), ast_conference::list, and NULL.

Referenced by complete_meetmecmd_list(), complete_meetmecmd_lock(), and complete_meetmecmd_mute_kick().

◆ complete_meetmecmd_list()

static char * complete_meetmecmd_list ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 1636 of file app_meetme.c.

1637{
1638 int len;
1639
1640 if (pos == 2) {
1641 len = strlen(word);
1642 if (!strncasecmp(word, STR_CONCISE, len)) {
1643 if (state == 0) {
1644 return ast_strdup(STR_CONCISE);
1645 }
1646 --state;
1647 }
1648
1649 return complete_confno(word, state);
1650 }
1651 if (pos == 3 && state == 0) {
1652 char *saved = NULL;
1653 char *myline;
1654 char *confno;
1655
1656 /* Extract the confno from the command line. */
1657 myline = ast_strdupa(line);
1658 strtok_r(myline, " ", &saved);
1659 strtok_r(NULL, " ", &saved);
1660 confno = strtok_r(NULL, " ", &saved);
1661
1662 if (!strcasecmp(confno, STR_CONCISE)) {
1663 /* There is nothing valid in this position now. */
1664 return NULL;
1665 }
1666
1667 len = strlen(word);
1668 if (!strncasecmp(word, STR_CONCISE, len)) {
1669 return ast_strdup(STR_CONCISE);
1670 }
1671 }
1672 return NULL;
1673}
static char * complete_confno(const char *word, int state)
Definition: app_meetme.c:1547
#define STR_CONCISE
Definition: app_meetme.c:656
enum cc_state state
Definition: ccss.c:393

References ast_strdup, ast_strdupa, complete_confno(), ast_conference::confno, len(), NULL, state, and STR_CONCISE.

Referenced by meetme_show_cmd().

◆ complete_meetmecmd_lock()

static char * complete_meetmecmd_lock ( const char *  word,
int  pos,
int  state 
)
static

Definition at line 1628 of file app_meetme.c.

1629{
1630 if (pos == 2) {
1631 return complete_confno(word, state);
1632 }
1633 return NULL;
1634}

References complete_confno(), and NULL.

Referenced by meetme_lock_cmd().

◆ complete_meetmecmd_mute_kick()

static char * complete_meetmecmd_mute_kick ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 1588 of file app_meetme.c.

1589{
1590 if (pos == 2) {
1591 return complete_confno(word, state);
1592 }
1593 if (pos == 3) {
1594 int len = strlen(word);
1595 char *ret = NULL;
1596 char *saved = NULL;
1597 char *myline;
1598 char *confno;
1599 struct ast_conference *cnf;
1600
1601 if (!strncasecmp(word, "all", len)) {
1602 if (state == 0) {
1603 return ast_strdup("all");
1604 }
1605 --state;
1606 }
1607
1608 /* Extract the confno from the command line. */
1609 myline = ast_strdupa(line);
1610 strtok_r(myline, " ", &saved);
1611 strtok_r(NULL, " ", &saved);
1612 confno = strtok_r(NULL, " ", &saved);
1613
1615 AST_LIST_TRAVERSE(&confs, cnf, list) {
1616 if (!strcmp(confno, cnf->confno)) {
1617 ret = complete_userno(cnf, word, state);
1618 break;
1619 }
1620 }
1622
1623 return ret;
1624 }
1625 return NULL;
1626}
static char * complete_userno(struct ast_conference *cnf, const char *word, int state)
Definition: app_meetme.c:1566

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdup, ast_strdupa, complete_confno(), complete_userno(), ast_conference::confno, len(), ast_conference::list, NULL, and state.

Referenced by meetme_kick_cmd(), and meetme_mute_cmd().

◆ complete_userno()

static char * complete_userno ( struct ast_conference cnf,
const char *  word,
int  state 
)
static

Definition at line 1566 of file app_meetme.c.

1567{
1568 char usrno[50];
1569 struct ao2_iterator iter;
1570 struct ast_conf_user *usr;
1571 char *ret = NULL;
1572 int which = 0;
1573 int len = strlen(word);
1574
1575 iter = ao2_iterator_init(cnf->usercontainer, 0);
1576 for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) {
1577 snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
1578 if (!strncmp(word, usrno, len) && ++which > state) {
1579 ao2_ref(usr, -1);
1580 ret = ast_strdup(usrno);
1581 break;
1582 }
1583 }
1584 ao2_iterator_destroy(&iter);
1585 return ret;
1586}

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_strdup, len(), NULL, ast_conf_user::user_no, and ast_conference::usercontainer.

Referenced by complete_meetmecmd_mute_kick().

◆ conf_exec()

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

The meetme() application.

Definition at line 4389 of file app_meetme.c.

4390{
4391 int res = -1;
4392 char confno[MAX_CONFNUM] = "";
4393 int allowretry = 0;
4394 int retrycnt = 0;
4395 struct ast_conference *cnf = NULL;
4396 struct ast_flags64 confflags = {0};
4397 struct ast_flags config_flags = { 0 };
4398 int dynamic = 0;
4399 int empty = 0, empty_no_pin = 0;
4400 int always_prompt = 0;
4401 const char *notdata;
4402 char *info, the_pin[MAX_PIN] = "";
4404 AST_APP_ARG(confno);
4406 AST_APP_ARG(pin);
4407 );
4408 char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
4409
4410 if (ast_strlen_zero(data)) {
4411 allowretry = 1;
4412 notdata = "";
4413 } else {
4414 notdata = data;
4415 }
4416
4417 if (ast_channel_state(chan) != AST_STATE_UP)
4418 ast_answer(chan);
4419
4420 info = ast_strdupa(notdata);
4421
4423
4424 if (args.confno) {
4425 ast_copy_string(confno, args.confno, sizeof(confno));
4426 if (ast_strlen_zero(confno)) {
4427 allowretry = 1;
4428 }
4429 }
4430
4431 if (args.pin)
4432 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
4433
4434 if (args.options) {
4435 ast_app_parse_options64(meetme_opts, &confflags, optargs, args.options);
4436 dynamic = ast_test_flag64(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
4438 strcpy(the_pin, "q");
4439
4440 empty = ast_test_flag64(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
4441 empty_no_pin = ast_test_flag64(&confflags, CONFFLAG_EMPTYNOPIN);
4442 always_prompt = ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
4443 }
4444
4445 do {
4446 if (retrycnt > 3)
4447 allowretry = 0;
4448 if (empty) {
4449 int i;
4450 struct ast_config *cfg;
4451 struct ast_variable *var;
4452 int confno_int;
4453
4454 /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
4455 if ((empty_no_pin) || (!dynamic)) {
4456 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
4457 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
4458 var = ast_variable_browse(cfg, "rooms");
4459 while (var) {
4460 char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
4461 if (!strcasecmp(var->name, "conf")) {
4462 int found = 0;
4463 ast_copy_string(parse, var->value, sizeof(parse));
4464 confno_tmp = strsep(&stringp, "|,");
4465 if (!dynamic) {
4466 /* For static: run through the list and see if this conference is empty */
4468 AST_LIST_TRAVERSE(&confs, cnf, list) {
4469 if (!strcmp(confno_tmp, cnf->confno)) {
4470 /* The conference exists, therefore it's not empty */
4471 found = 1;
4472 break;
4473 }
4474 }
4476 cnf = NULL;
4477 if (!found) {
4478 /* At this point, we have a confno_tmp (static conference) that is empty */
4479 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
4480 /* Case 1: empty_no_pin and pin is nonexistent (NULL)
4481 * Case 2: empty_no_pin and pin is blank (but not NULL)
4482 * Case 3: not empty_no_pin
4483 */
4484 ast_copy_string(confno, confno_tmp, sizeof(confno));
4485 break;
4486 }
4487 }
4488 }
4489 }
4490 var = var->next;
4491 }
4492 ast_config_destroy(cfg);
4493 }
4494
4495 if (ast_strlen_zero(confno) && (cfg = ast_load_realtime_multientry("meetme", "confno LIKE", "%", SENTINEL))) {
4496 const char *catg;
4497 for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
4498 const char *confno_tmp = ast_variable_retrieve(cfg, catg, "confno");
4499 const char *pin_tmp = ast_variable_retrieve(cfg, catg, "pin");
4500 if (ast_strlen_zero(confno_tmp)) {
4501 continue;
4502 }
4503 if (!dynamic) {
4504 int found = 0;
4505 /* For static: run through the list and see if this conference is empty */
4507 AST_LIST_TRAVERSE(&confs, cnf, list) {
4508 if (!strcmp(confno_tmp, cnf->confno)) {
4509 /* The conference exists, therefore it's not empty */
4510 found = 1;
4511 break;
4512 }
4513 }
4515 if (!found) {
4516 /* At this point, we have a confno_tmp (realtime conference) that is empty */
4517 if ((empty_no_pin && ast_strlen_zero(pin_tmp)) || (!empty_no_pin)) {
4518 /* Case 1: empty_no_pin and pin is nonexistent (NULL)
4519 * Case 2: empty_no_pin and pin is blank (but not NULL)
4520 * Case 3: not empty_no_pin
4521 */
4522 ast_copy_string(confno, confno_tmp, sizeof(confno));
4523 break;
4524 }
4525 }
4526 }
4527 }
4528 ast_config_destroy(cfg);
4529 }
4530 }
4531
4532 /* Select first conference number not in use */
4533 if (ast_strlen_zero(confno) && dynamic) {
4535 for (i = 0; i < ARRAY_LEN(conf_map); i++) {
4536 if (!conf_map[i]) {
4537 snprintf(confno, sizeof(confno), "%d", i);
4538 conf_map[i] = 1;
4539 break;
4540 }
4541 }
4543 }
4544
4545 /* Not found? */
4546 if (ast_strlen_zero(confno)) {
4547 res = ast_streamfile(chan, "conf-noempty", ast_channel_language(chan));
4548 ast_test_suite_event_notify("PLAYBACK", "Message: conf-noempty");
4549 if (!res)
4550 ast_waitstream(chan, "");
4551 } else {
4552 if (sscanf(confno, "%30d", &confno_int) == 1) {
4553 if (!ast_test_flag64(&confflags, CONFFLAG_QUIET)) {
4554 res = ast_streamfile(chan, "conf-enteringno", ast_channel_language(chan));
4555 if (!res) {
4556 ast_waitstream(chan, "");
4557 res = ast_say_digits(chan, confno_int, "", ast_channel_language(chan));
4558 }
4559 }
4560 } else {
4561 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
4562 }
4563 }
4564 }
4565
4566 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
4567 /* Prompt user for conference number */
4568 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
4569 if (res < 0) {
4570 /* Don't try to validate when we catch an error */
4571 confno[0] = '\0';
4572 allowretry = 0;
4573 break;
4574 }
4575 }
4576 if (!ast_strlen_zero(confno)) {
4577 /* Check the validity of the conference */
4578 cnf = find_conf(chan, confno, 1, dynamic, the_pin,
4579 sizeof(the_pin), 1, &confflags);
4580 if (!cnf) {
4581 int too_early = 0;
4582
4583 cnf = find_conf_realtime(chan, confno, 1, dynamic,
4584 the_pin, sizeof(the_pin), 1, &confflags, &too_early, optargs);
4585 if (rt_schedule && too_early)
4586 allowretry = 0;
4587 }
4588
4589 if (!cnf) {
4590 if (allowretry) {
4591 confno[0] = '\0';
4592 res = ast_streamfile(chan, "conf-invalid", ast_channel_language(chan));
4593 if (!res)
4594 ast_waitstream(chan, "");
4595 res = -1;
4596 }
4597 } else {
4598 /* Conference requires a pin for specified access level */
4599 int req_pin = !ast_strlen_zero(cnf->pin) ||
4600 (!ast_strlen_zero(cnf->pinadmin) &&
4601 ast_test_flag64(&confflags, CONFFLAG_ADMIN));
4602 /* The following logic was derived from a
4603 * 4 variable truth table and defines which
4604 * circumstances are not exempt from pin
4605 * checking.
4606 * If this needs to be modified, write the
4607 * truth table back out from the boolean
4608 * expression AB+A'D+C', change the erroneous
4609 * result, and rederive the expression.
4610 * Variables:
4611 * A: pin provided?
4612 * B: always prompt?
4613 * C: dynamic?
4614 * D: has users? */
4615 int not_exempt = !cnf->isdynamic;
4616 not_exempt = not_exempt || (!ast_strlen_zero(args.pin) && ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT));
4617 not_exempt = not_exempt || (ast_strlen_zero(args.pin) && cnf->users);
4618 if (req_pin && not_exempt) {
4619 char pin[MAX_PIN] = "";
4620 int j;
4621
4622 /* Allow the pin to be retried up to 3 times */
4623 for (j = 0; j < 3; j++) {
4624 if (*the_pin && (always_prompt == 0)) {
4625 ast_copy_string(pin, the_pin, sizeof(pin));
4626 res = 0;
4627 } else {
4628 /* Prompt user for pin if pin is required */
4629 ast_test_suite_event_notify("PLAYBACK", "Message: conf-getpin\r\n"
4630 "Channel: %s",
4631 ast_channel_name(chan));
4632 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
4633 }
4634 if (res >= 0) {
4635 if ((!strcasecmp(pin, cnf->pin) &&
4636 (ast_strlen_zero(cnf->pinadmin) ||
4637 !ast_test_flag64(&confflags, CONFFLAG_ADMIN))) ||
4638 (!ast_strlen_zero(cnf->pinadmin) &&
4639 !strcasecmp(pin, cnf->pinadmin))) {
4640 /* Pin correct */
4641 allowretry = 0;
4642 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
4643 if (!ast_strlen_zero(cnf->adminopts)) {
4644 char *opts = ast_strdupa(cnf->adminopts);
4645 ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
4646 }
4647 } else {
4648 if (!ast_strlen_zero(cnf->useropts)) {
4649 char *opts = ast_strdupa(cnf->useropts);
4650 ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
4651 }
4652 }
4653 /* Run the conference */
4654 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
4655 res = conf_run(chan, cnf, &confflags, optargs);
4656 break;
4657 } else {
4658 /* Pin invalid */
4659 if (!ast_streamfile(chan, "conf-invalidpin", ast_channel_language(chan))) {
4660 res = ast_waitstream(chan, AST_DIGIT_ANY);
4661 ast_stopstream(chan);
4662 } else {
4663 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
4664 break;
4665 }
4666 if (res < 0)
4667 break;
4668 pin[0] = res;
4669 pin[1] = '\0';
4670 res = -1;
4671 if (allowretry)
4672 confno[0] = '\0';
4673 }
4674 } else {
4675 /* failed when getting the pin */
4676 res = -1;
4677 allowretry = 0;
4678 /* see if we need to get rid of the conference */
4679 break;
4680 }
4681
4682 /* Don't retry pin with a static pin */
4683 if (*the_pin && (always_prompt == 0)) {
4684 break;
4685 }
4686 }
4687 } else {
4688 /* No pin required */
4689 allowretry = 0;
4690
4691 /* For RealTime conferences without a pin
4692 * should still support loading options
4693 */
4694 if (!ast_strlen_zero(cnf->useropts)) {
4695 char *opts = ast_strdupa(cnf->useropts);
4696 ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
4697 }
4698
4699 /* Run the conference */
4700 res = conf_run(chan, cnf, &confflags, optargs);
4701 }
4702 dispose_conf(cnf);
4703 cnf = NULL;
4704 }
4705 }
4706 } while (allowretry);
4707
4708 if (cnf)
4709 dispose_conf(cnf);
4710
4711 return res;
4712}
static const struct ast_app_option meetme_opts[128]
Definition: app_meetme.c:810
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_flags64 *confflags, int *too_early, char **optargs)
Definition: app_meetme.c:4053
#define CONFIG_FILE_NAME
Definition: app_meetme.c:655
#define MAX_PIN
Definition: app_meetme.c:828
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
Definition: app_meetme.c:2740
#define MAX_CONFNUM
Definition: app_meetme.c:827
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_flags64 *confflags)
Definition: app_meetme.c:4240
static int rt_schedule
Definition: app_meetme.c:818
#define MAX_SETTINGS
Definition: app_meetme.c:832
#define var
Definition: ast_expr2f.c:605
const char * ast_channel_language(const struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2805
#define SENTINEL
Definition: compiler.h:87
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
#define AST_DIGIT_ANY
Definition: file.h:48
enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
Plays a stream and gets DTMF data from a channel.
Definition: main/app.c:188
int ast_app_parse_options64(const struct ast_app_option *options, struct ast_flags64 *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3061
char * strsep(char **str, const char *delims)
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3622
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:783
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
def info(msg)
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8253
char * recordingformat
Definition: app_meetme.c:872
const char * useropts
Definition: app_meetme.c:877
char * recordingfilename
Definition: app_meetme.c:871
const char * adminopts
Definition: app_meetme.c:878
Structure used to handle a large number of boolean flags == used only in app_dial?
Definition: utils.h:204
Structure used to handle boolean flags.
Definition: utils.h:199
Structure for variables, used for configurations and for channel variables.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
static struct test_options options
#define ARRAY_LEN(a)
Definition: utils.h:666

References ast_conference::adminopts, args, ARRAY_LEN, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_app_parse_options64(), ast_category_browse(), ast_channel_language(), ast_channel_name(), 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_load_realtime_multientry(), ast_log, ast_say_digits(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag64, ast_test_suite_event_notify, ast_variable_browse(), ast_variable_retrieve(), ast_verb, ast_waitstream(), conf_map, conf_run(), CONFFLAG_ADMIN, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFFLAG_QUIET, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_conference::confno, dispose_conf(), find_conf(), find_conf_realtime(), sip_to_pjsip::info(), ast_conference::isdynamic, LOG_ERROR, LOG_WARNING, MAX_CONFNUM, MAX_PIN, MAX_SETTINGS, meetme_opts, NULL, OPT_ARG_ARRAY_SIZE, options, ast_conference::pin, ast_conference::pinadmin, ast_conference::recordingfilename, ast_conference::recordingformat, rt_schedule, SENTINEL, strsep(), ast_conference::useropts, ast_conference::users, and var.

Referenced by load_module().

◆ conf_flush()

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

Definition at line 1944 of file app_meetme.c.

1945{
1946 int x;
1947
1948 /* read any frames that may be waiting on the channel
1949 and throw them away
1950 */
1951 if (chan) {
1952 struct ast_frame *f;
1953
1954 /* when no frames are available, this will wait
1955 for 1 millisecond maximum
1956 */
1957 while (ast_waitfor(chan, 1) > 0) {
1958 f = ast_read(chan);
1959 if (f)
1960 ast_frfree(f);
1961 else /* channel was hung up or something else happened */
1962 break;
1963 }
1964 }
1965
1966 /* flush any data sitting in the pseudo channel */
1967 x = DAHDI_FLUSH_ALL;
1968 if (ioctl(fd, DAHDI_FLUSH, &x))
1969 ast_log(LOG_WARNING, "Error flushing channel\n");
1970
1971}
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3162
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
#define ast_frfree(fr)
Data structure associated with a single frame of data.

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

Referenced by conf_run().

◆ conf_free()

static int conf_free ( struct ast_conference conf)
static

Remove the conference from the list and free it.

We assume that this was called while holding conflock.

Definition at line 1976 of file app_meetme.c.

1977{
1978 int x;
1979 struct announce_listitem *item;
1980
1981 AST_LIST_REMOVE(&confs, conf, list);
1982
1983 meetme_stasis_generate_msg(conf, NULL, NULL, meetme_end_type(), NULL);
1984
1985 if (conf->recording == MEETME_RECORD_ACTIVE) {
1986 conf->recording = MEETME_RECORD_TERMINATE;
1988 while (1) {
1989 usleep(1);
1991 if (conf->recording == MEETME_RECORD_OFF)
1992 break;
1994 }
1995 }
1996
1997 for (x = 0; x < AST_FRAME_BITS; x++) {
1998 if (conf->transframe[x])
1999 ast_frfree(conf->transframe[x]);
2000 if (conf->transpath[x])
2001 ast_translator_free_path(conf->transpath[x]);
2002 }
2003 if (conf->announcethread != AST_PTHREADT_NULL) {
2004 ast_mutex_lock(&conf->announcelistlock);
2005 conf->announcethread_stop = 1;
2007 ast_cond_signal(&conf->announcelist_addition);
2008 ast_mutex_unlock(&conf->announcelistlock);
2009 pthread_join(conf->announcethread, NULL);
2010
2011 while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
2012 /* If it's a voicemail greeting file we don't want to remove it */
2013 if (!item->vmrec){
2014 ast_filedelete(item->namerecloc, NULL);
2015 }
2016 ao2_ref(item, -1);
2017 }
2018 ast_mutex_destroy(&conf->announcelistlock);
2019 }
2020
2021 if (conf->origframe)
2022 ast_frfree(conf->origframe);
2023 ast_hangup(conf->lchan);
2024 ast_hangup(conf->chan);
2025 if (conf->fd >= 0)
2026 close(conf->fd);
2027 if (conf->recordingfilename) {
2028 ast_free(conf->recordingfilename);
2029 }
2030 if (conf->usercontainer) {
2031 ao2_ref(conf->usercontainer, -1);
2032 }
2033 if (conf->recordingformat) {
2034 ast_free(conf->recordingformat);
2035 }
2036 ast_mutex_destroy(&conf->playlock);
2037 ast_mutex_destroy(&conf->listenlock);
2038 ast_mutex_destroy(&conf->recordthreadlock);
2039 ast_mutex_destroy(&conf->announcethreadlock);
2040 ast_free(conf);
2041
2042 return 0;
2043}
static void meetme_stasis_generate_msg(struct ast_conference *meetme_conference, struct ast_channel *chan, struct ast_conf_user *user, struct stasis_message_type *message_type, struct ast_json *extras)
Definition: app_meetme.c:1165
#define AST_FRAME_BITS
Definition: app_meetme.c:676
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2471
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1148
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:856
#define ast_cond_signal(cond)
Definition: lock.h:203
static struct aco_type item
Definition: test_config.c:1463
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition: translate.c:476

References ao2_ref, ast_cond_signal, ast_filedelete(), AST_FRAME_BITS, ast_free, ast_frfree, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_translator_free_path(), item, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, meetme_stasis_generate_msg(), and NULL.

Referenced by dispose_conf().

◆ conf_play()

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

Definition at line 1348 of file app_meetme.c.

1349{
1350 unsigned char *data;
1351 int len;
1352 int res = -1;
1353
1354 ast_test_suite_event_notify("CONFPLAY", "Channel: %s\r\n"
1355 "Conference: %s\r\n"
1356 "Marked: %d",
1357 ast_channel_name(chan),
1358 conf->confno,
1359 conf->markedusers);
1360
1361 if (!ast_check_hangup(chan))
1362 res = ast_autoservice_start(chan);
1363
1365
1366 switch(sound) {
1367 case ENTER:
1368 data = enter;
1369 len = sizeof(enter);
1370 break;
1371 case LEAVE:
1372 data = leave;
1373 len = sizeof(leave);
1374 break;
1375 default:
1376 data = NULL;
1377 len = 0;
1378 }
1379 if (data) {
1380 careful_write(conf->fd, data, len, 1);
1381 }
1382
1384
1385 if (!res)
1387}
static int careful_write(int fd, unsigned char *data, int len, int block)
Definition: app_meetme.c:1230
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
static unsigned char enter[]
Definition: enter.h:12
static unsigned char leave[]
Definition: leave.h:12

References ast_autoservice_start(), ast_autoservice_stop(), ast_channel_name(), ast_check_hangup(), AST_LIST_LOCK, AST_LIST_UNLOCK, ast_test_suite_event_notify, careful_write(), ENTER, enter, LEAVE, leave, len(), and NULL.

Referenced by conf_run().

◆ conf_queue_dtmf()

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

Definition at line 2045 of file app_meetme.c.

2047{
2048 struct ast_conf_user *user;
2049 struct ao2_iterator user_iter;
2050
2051 user_iter = ao2_iterator_init(conf->usercontainer, 0);
2052 while ((user = ao2_iterator_next(&user_iter))) {
2053 if (user == sender) {
2054 ao2_ref(user, -1);
2055 continue;
2056 }
2057 if (ast_write(user->chan, f) < 0)
2058 ast_log(LOG_WARNING, "Error writing frame to channel %s\n", ast_channel_name(user->chan));
2059 ao2_ref(user, -1);
2060 }
2061 ao2_iterator_destroy(&user_iter);
2062}
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:5144

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_name(), ast_log, ast_write(), LOG_WARNING, and user.

Referenced by conf_run().

◆ conf_run()

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

Definition at line 2740 of file app_meetme.c.

2741{
2742 struct ast_conf_user *user = NULL;
2743 int fd;
2744 struct dahdi_confinfo dahdic, dahdic_empty;
2745 struct ast_frame *f;
2746 struct ast_channel *c;
2747 struct ast_frame fr;
2748 int outfd;
2749 int ms;
2750 int nfds;
2751 int res;
2752 int retrydahdi;
2753 int origfd;
2754 int musiconhold = 0, mohtempstopped = 0;
2755 int firstpass = 0;
2756 int lastmarked = 0;
2757 int currentmarked = 0;
2758 int ret = -1;
2759 int x;
2760 enum menu_modes menu_mode = MENU_DISABLED;
2761 int talkreq_manager = 0;
2762 int using_pseudo = 0;
2763 int duration = 20;
2764 int sent_event = 0;
2765 int checked = 0;
2766 int announcement_played = 0;
2767 struct timeval now;
2768 struct ast_dsp *dsp = NULL;
2769 struct ast_app *agi_app;
2770 char *agifile;
2771 const char *agifiledefault = "conf-background.agi", *tmpvar;
2772 char meetmesecs[30] = "";
2773 char exitcontext[AST_MAX_CONTEXT] = "";
2774 char recordingtmp[AST_MAX_EXTENSION * 2] = "";
2775 char members[10] = "";
2776 int dtmf = 0, opt_waitmarked_timeout = 0;
2777 time_t timeout = 0;
2778 struct dahdi_bufferinfo bi;
2779 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
2780 char *buf = __buf + AST_FRIENDLY_OFFSET;
2781 char *exitkeys = NULL;
2782 unsigned int calldurationlimit = 0;
2783 long timelimit = 0;
2784 long play_warning = 0;
2785 long warning_freq = 0;
2786 const char *warning_sound = NULL;
2787 const char *end_sound = NULL;
2788 char *parse;
2789 long time_left_ms = 0;
2790 struct timeval nexteventts = { 0, };
2791 int to;
2792 int setusercount = 0;
2793 int confsilence = 0, totalsilence = 0;
2794 char *mailbox, *context;
2796
2797 if (!cap_slin) {
2798 goto conf_run_cleanup;
2799 }
2801
2802 if (!(user = ao2_alloc(sizeof(*user), NULL))) {
2803 goto conf_run_cleanup;
2804 }
2805
2806 /* Possible timeout waiting for marked user */
2807 if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
2809 (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
2810 (opt_waitmarked_timeout > 0)) {
2811 timeout = time(NULL) + opt_waitmarked_timeout;
2812 }
2813
2815 calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
2816 ast_verb(3, "Setting call duration limit to %u seconds.\n", calldurationlimit);
2817 }
2818
2820 char *limit_str, *warning_str, *warnfreq_str;
2821 const char *var;
2822
2823 parse = optargs[OPT_ARG_DURATION_LIMIT];
2824 limit_str = strsep(&parse, ":");
2825 warning_str = strsep(&parse, ":");
2826 warnfreq_str = parse;
2827
2828 timelimit = atol(limit_str);
2829 if (warning_str)
2830 play_warning = atol(warning_str);
2831 if (warnfreq_str)
2832 warning_freq = atol(warnfreq_str);
2833
2834 if (!timelimit) {
2835 timelimit = play_warning = warning_freq = 0;
2836 warning_sound = NULL;
2837 } else if (play_warning > timelimit) {
2838 if (!warning_freq) {
2839 play_warning = 0;
2840 } else {
2841 while (play_warning > timelimit)
2842 play_warning -= warning_freq;
2843 if (play_warning < 1)
2844 play_warning = warning_freq = 0;
2845 }
2846 }
2847
2848 ast_verb(3, "Setting conference duration limit to: %ldms.\n", timelimit);
2849 if (play_warning) {
2850 ast_verb(3, "Setting warning time to %ldms from the conference duration limit.\n", play_warning);
2851 }
2852 if (warning_freq) {
2853 ast_verb(3, "Setting warning frequency to %ldms.\n", warning_freq);
2854 }
2855
2856 ast_channel_lock(chan);
2857 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
2858 var = ast_strdupa(var);
2859 }
2860 ast_channel_unlock(chan);
2861
2862 warning_sound = var ? var : "timeleft";
2863
2864 ast_channel_lock(chan);
2865 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
2866 var = ast_strdupa(var);
2867 }
2868 ast_channel_unlock(chan);
2869
2870 end_sound = var ? var : NULL;
2871
2872 /* undo effect of S(x) in case they are both used */
2873 calldurationlimit = 0;
2874 /* more efficient do it like S(x) does since no advanced opts */
2875 if (!play_warning && !end_sound && timelimit) {
2876 calldurationlimit = timelimit / 1000;
2877 timelimit = play_warning = warning_freq = 0;
2878 } else {
2879 ast_debug(2, "Limit Data for this call:\n");
2880 ast_debug(2, "- timelimit = %ld\n", timelimit);
2881 ast_debug(2, "- play_warning = %ld\n", play_warning);
2882 ast_debug(2, "- warning_freq = %ld\n", warning_freq);
2883 ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
2884 ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF");
2885 }
2886 }
2887
2888 /* Get exit keys */
2889 if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
2890 if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
2891 exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
2892 else
2893 exitkeys = ast_strdupa("#"); /* Default */
2894 }
2895
2896 if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
2897 if (!conf->recordingfilename) {
2898 const char *var;
2899 ast_channel_lock(chan);
2900 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
2901 conf->recordingfilename = ast_strdup(var);
2902 }
2903 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
2904 conf->recordingformat = ast_strdup(var);
2905 }
2906 ast_channel_unlock(chan);
2907 if (!conf->recordingfilename) {
2908 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
2909 conf->recordingfilename = ast_strdup(recordingtmp);
2910 }
2911 if (!conf->recordingformat) {
2912 conf->recordingformat = ast_strdup("wav");
2913 }
2914 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
2915 conf->confno, conf->recordingfilename, conf->recordingformat);
2916 }
2917 }
2918
2919 ast_mutex_lock(&conf->recordthreadlock);
2920 if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
2921 ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
2924 dahdic.chan = 0;
2925 dahdic.confno = conf->dahdiconf;
2926 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
2927 if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
2928 ast_log(LOG_WARNING, "Error starting listen channel\n");
2929 ast_hangup(conf->lchan);
2930 conf->lchan = NULL;
2931 } else {
2933 }
2934 }
2935 ast_mutex_unlock(&conf->recordthreadlock);
2936
2937 ast_mutex_lock(&conf->announcethreadlock);
2938 if ((conf->announcethread == AST_PTHREADT_NULL) && !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
2940 ast_mutex_init(&conf->announcelistlock);
2941 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
2943 }
2944 ast_mutex_unlock(&conf->announcethreadlock);
2945
2946 time(&user->jointime);
2947
2948 user->timelimit = timelimit;
2949 user->play_warning = play_warning;
2950 user->warning_freq = warning_freq;
2951 user->warning_sound = warning_sound;
2952 user->end_sound = end_sound;
2953
2954 if (calldurationlimit > 0) {
2955 time(&user->kicktime);
2956 user->kicktime = user->kicktime + calldurationlimit;
2957 }
2958
2959 if (ast_tvzero(user->start_time))
2960 user->start_time = ast_tvnow();
2961 time_left_ms = user->timelimit;
2962
2963 if (user->timelimit) {
2964 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
2965 nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
2966 }
2967
2968 if (conf->locked && (!ast_test_flag64(confflags, CONFFLAG_ADMIN))) {
2969 /* Sorry, but this conference is locked! */
2970 if (!ast_streamfile(chan, "conf-locked", ast_channel_language(chan)))
2971 ast_waitstream(chan, "");
2972 goto outrun;
2973 }
2974
2975 ast_mutex_lock(&conf->playlock);
2976
2977 if (rt_schedule && conf->maxusers) {
2978 if (conf->users >= conf->maxusers) {
2979 /* Sorry, but this confernce has reached the participant limit! */
2980 ast_mutex_unlock(&conf->playlock);
2981 if (!ast_streamfile(chan, "conf-full", ast_channel_language(chan)))
2982 ast_waitstream(chan, "");
2983 goto outrun;
2984 }
2985 }
2986
2987 ao2_lock(conf->usercontainer);
2988 ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &user->user_no);
2989 user->user_no++;
2990 ao2_link(conf->usercontainer, user);
2991 ao2_unlock(conf->usercontainer);
2992
2993 user->chan = chan;
2994 user->userflags = *confflags;
2995 user->adminflags = ast_test_flag64(confflags, CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
2996 if (!ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
2997 user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
2998 }
2999 user->talking = -1;
3000
3001 ast_mutex_unlock(&conf->playlock);
3002
3004 char destdir[PATH_MAX];
3005
3006 snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
3007
3008 if (ast_mkdir(destdir, 0777) != 0) {
3009 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
3010 goto outrun;
3011 }
3012
3015 mailbox = strsep(&context, "@");
3016
3017 if (ast_strlen_zero(mailbox)) {
3018 /* invalid input, clear the v flag*/
3020 ast_log(LOG_WARNING,"You must specify a mailbox in the v() option\n");
3021 } else {
3022 if (ast_strlen_zero(context)) {
3023 context = "default";
3024 }
3025 /* if there is no mailbox we don't need to do this logic */
3026 snprintf(user->namerecloc, sizeof(user->namerecloc),
3027 "%s/voicemail/%s/%s/greet",ast_config_AST_SPOOL_DIR,context,mailbox);
3028
3029 /* if the greeting doesn't exist then use the temp file method instead, clear flag v */
3030 if (!ast_fileexists(user->namerecloc, NULL, NULL)){
3031 snprintf(user->namerecloc, sizeof(user->namerecloc),
3032 "%s/meetme-username-%s-%d", destdir,
3033 conf->confno, user->user_no);
3035 }
3036 }
3037 } else {
3038 snprintf(user->namerecloc, sizeof(user->namerecloc),
3039 "%s/meetme-username-%s-%d", destdir,
3040 conf->confno, user->user_no);
3041 }
3042
3043 res = 0;
3044 if (ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) && !ast_fileexists(user->namerecloc, NULL, NULL))
3045 res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
3046 else if (ast_test_flag64(confflags, CONFFLAG_INTROUSER) && !ast_fileexists(user->namerecloc, NULL, NULL))
3047 res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
3048 if (res == -1)
3049 goto outrun;
3050
3051 }
3052
3053 ast_mutex_lock(&conf->playlock);
3054
3055 if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER))
3056 conf->markedusers++;
3057 conf->users++;
3058 if (rt_log_members) {
3059 /* Update table */
3060 snprintf(members, sizeof(members), "%d", conf->users);
3062 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
3063 "members", RQ_UINTEGER1, strlen(members),
3064 NULL);
3065 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
3066 }
3067 setusercount = 1;
3068
3069 /* This device changed state now - if this is the first user */
3070 if (conf->users == 1)
3072
3073 ast_mutex_unlock(&conf->playlock);
3074
3075 /* return the unique ID of the conference */
3076 pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
3077
3078 if (ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT)) {
3079 ast_channel_lock(chan);
3080 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
3081 ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
3082 } else {
3084 }
3085 ast_channel_unlock(chan);
3086 }
3087
3088 /* Play an arbitrary intro message */
3089 if (ast_test_flag64(confflags, CONFFLAG_INTROMSG) &&
3090 !ast_strlen_zero(optargs[OPT_ARG_INTROMSG])) {
3091 if (!ast_streamfile(chan, optargs[OPT_ARG_INTROMSG], ast_channel_language(chan))) {
3092 ast_waitstream(chan, "");
3093 }
3094 }
3095
3097 if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED))
3098 if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan)))
3099 ast_waitstream(chan, "");
3100 if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && conf->markedusers == 0)
3101 if (!ast_streamfile(chan, "conf-waitforleader", ast_channel_language(chan)))
3102 ast_waitstream(chan, "");
3103 }
3104
3105 if (ast_test_flag64(confflags, CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
3106 int keepplaying = 1;
3107
3108 if (conf->users == 2) {
3109 if (!ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
3110 res = ast_waitstream(chan, AST_DIGIT_ANY);
3111 ast_stopstream(chan);
3112 if (res > 0)
3113 keepplaying = 0;
3114 else if (res == -1)
3115 goto outrun;
3116 }
3117 } else {
3118 if (!ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
3119 res = ast_waitstream(chan, AST_DIGIT_ANY);
3120 ast_stopstream(chan);
3121 if (res > 0)
3122 keepplaying = 0;
3123 else if (res == -1)
3124 goto outrun;
3125 }
3126 if (keepplaying) {
3127 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3128 if (res > 0)
3129 keepplaying = 0;
3130 else if (res == -1)
3131 goto outrun;
3132 }
3133 if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
3134 res = ast_waitstream(chan, AST_DIGIT_ANY);
3135 ast_stopstream(chan);
3136 if (res > 0)
3137 keepplaying = 0;
3138 else if (res == -1)
3139 goto outrun;
3140 }
3141 }
3142 }
3143
3145 /* We're leaving this alone until the state gets changed to up */
3146 ast_indicate(chan, -1);
3147 }
3148
3149 if (ast_set_write_format(chan, ast_format_slin) < 0) {
3150 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", ast_channel_name(chan));
3151 goto outrun;
3152 }
3153
3154 if (ast_set_read_format(chan, ast_format_slin) < 0) {
3155 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", ast_channel_name(chan));
3156 goto outrun;
3157 }
3158
3159 /* Reduce background noise from each participant */
3160 if (!ast_test_flag64(confflags, CONFFLAG_DONT_DENOISE)) {
3161 ast_func_write(chan, "DENOISE(rx)", "on");
3162 }
3163
3164 retrydahdi = (strcasecmp(ast_channel_tech(chan)->type, "DAHDI") || (ast_channel_audiohooks(chan)) ? 1 : 0);
3165 user->dahdichannel = !retrydahdi;
3166
3167 dahdiretry:
3168 origfd = ast_channel_fd(chan, 0);
3169 if (retrydahdi) {
3170 /* open pseudo in non-blocking mode */
3171 fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
3172 if (fd < 0) {
3173 ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
3174 goto outrun;
3175 }
3176 using_pseudo = 1;
3177 /* Setup buffering information */
3178 memset(&bi, 0, sizeof(bi));
3179 bi.bufsize = CONF_SIZE / 2;
3180 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
3181 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
3182 bi.numbufs = audio_buffers;
3183 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
3184 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
3185 close(fd);
3186 goto outrun;
3187 }
3188 x = 1;
3189 if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
3190 ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
3191 close(fd);
3192 goto outrun;
3193 }
3194 nfds = 1;
3195 } else {
3196 /* XXX Make sure we're not running on a pseudo channel XXX */
3197 fd = ast_channel_fd(chan, 0);
3198 nfds = 0;
3199 }
3200 memset(&dahdic, 0, sizeof(dahdic));
3201 memset(&dahdic_empty, 0, sizeof(dahdic_empty));
3202 /* Check to see if we're in a conference... */
3203 dahdic.chan = 0;
3204 if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
3205 ast_log(LOG_WARNING, "Error getting conference\n");
3206 close(fd);
3207 goto outrun;
3208 }
3209 if (dahdic.confmode) {
3210 /* Whoa, already in a conference... Retry... */
3211 if (!retrydahdi) {
3212 ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
3213 retrydahdi = 1;
3214 goto dahdiretry;
3215 }
3216 }
3217 memset(&dahdic, 0, sizeof(dahdic));
3218 /* Add us to the conference */
3219 dahdic.chan = 0;
3220 dahdic.confno = conf->dahdiconf;
3221
3222 if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
3224 struct announce_listitem *item;
3225 if (!(item = ao2_alloc(sizeof(*item), NULL)))
3226 goto outrun;
3227 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
3228 ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
3229 item->confchan = conf->chan;
3230 item->confusers = conf->users;
3232 item->vmrec = 1;
3233 }
3234 item->announcetype = CONF_HASJOIN;
3235 ast_mutex_lock(&conf->announcelistlock);
3236 ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
3237 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
3238 ast_cond_signal(&conf->announcelist_addition);
3239 ast_mutex_unlock(&conf->announcelistlock);
3240
3241 while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
3242 ;
3243 }
3244 ao2_ref(item, -1);
3245 }
3246
3247 if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && !conf->markedusers)
3248 dahdic.confmode = DAHDI_CONF_CONF;
3249 else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
3250 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
3251 else if (ast_test_flag64(confflags, CONFFLAG_TALKER))
3252 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
3253 else
3254 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
3255
3256 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3257 ast_log(LOG_WARNING, "Error setting conference\n");
3258 close(fd);
3259 goto outrun;
3260 }
3261 ast_debug(1, "Placed channel %s in DAHDI conf %d\n", ast_channel_name(chan), conf->dahdiconf);
3262
3263 if (!sent_event) {
3264 meetme_stasis_generate_msg(conf, chan, user, meetme_join_type(), NULL);
3265 sent_event = 1;
3266 }
3267
3268 if (!firstpass && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
3269 !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3270 firstpass = 1;
3271 if (!ast_test_flag64(confflags, CONFFLAG_QUIET))
3273 (conf->markedusers >= 1))) {
3274 conf_play(chan, conf, ENTER);
3275 }
3276 }
3277
3278 conf_flush(fd, chan);
3279
3280 if (dsp)
3281 ast_dsp_free(dsp);
3282
3283 if (!(dsp = ast_dsp_new())) {
3284 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
3285 res = -1;
3286 }
3287
3288 if (ast_test_flag64(confflags, CONFFLAG_AGI)) {
3289 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
3290 or use default filename of conf-background.agi */
3291
3292 ast_channel_lock(chan);
3293 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
3294 agifile = ast_strdupa(tmpvar);
3295 } else {
3296 agifile = ast_strdupa(agifiledefault);
3297 }
3298 ast_channel_unlock(chan);
3299
3300 if (user->dahdichannel) {
3301 /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
3302 x = 1;
3303 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3304 }
3305 /* Find a pointer to the agi app and execute the script */
3306 agi_app = pbx_findapp("agi");
3307 if (agi_app) {
3308 ret = pbx_exec(chan, agi_app, agifile);
3309 } else {
3310 ast_log(LOG_WARNING, "Could not find application (agi)\n");
3311 ret = -2;
3312 }
3313 if (user->dahdichannel) {
3314 /* Remove CONFMUTE mode on DAHDI channel */
3315 x = 0;
3316 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3317 }
3318 } else {
3319 int lastusers = conf->users;
3320 if (user->dahdichannel && ast_test_flag64(confflags, CONFFLAG_STARMENU)) {
3321 /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
3322 x = 1;
3323 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3324 }
3325
3326 for (;;) {
3327 int menu_was_active = 0;
3328
3329 outfd = -1;
3330 ms = -1;
3331 now = ast_tvnow();
3332
3333 if (rt_schedule && conf->endtime) {
3334 char currenttime[32];
3335 long localendtime = 0;
3336 int extended = 0;
3337 struct ast_tm tm;
3338 struct ast_variable *var, *origvar;
3339 struct timeval tmp;
3340
3341 if (now.tv_sec % 60 == 0) {
3342 if (!checked) {
3343 ast_localtime(&now, &tm, NULL);
3344 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
3345 var = origvar = ast_load_realtime("meetme", "confno",
3346 conf->confno, "starttime <=", currenttime,
3347 "endtime >=", currenttime, NULL);
3348
3349 for ( ; var; var = var->next) {
3350 if (!strcasecmp(var->name, "endtime")) {
3351 struct ast_tm endtime_tm;
3352 ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
3353 tmp = ast_mktime(&endtime_tm, NULL);
3354 localendtime = tmp.tv_sec;
3355 }
3356 }
3357 ast_variables_destroy(origvar);
3358
3359 /* A conference can be extended from the
3360 Admin/User menu or by an external source */
3361 if (localendtime > conf->endtime){
3362 conf->endtime = localendtime;
3363 extended = 1;
3364 }
3365
3366 if (conf->endtime && (now.tv_sec >= conf->endtime)) {
3367 ast_verbose("Quitting time...\n");
3368 goto outrun;
3369 }
3370
3371 if (!announcement_played && conf->endalert) {
3372 if (now.tv_sec + conf->endalert >= conf->endtime) {
3373 if (!ast_streamfile(chan, "conf-will-end-in", ast_channel_language(chan)))
3374 ast_waitstream(chan, "");
3375 ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", ast_channel_language(chan));
3376 if (!ast_streamfile(chan, "minutes", ast_channel_language(chan)))
3377 ast_waitstream(chan, "");
3378 if (musiconhold) {
3379 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3380 }
3381 announcement_played = 1;
3382 }
3383 }
3384
3385 if (extended) {
3386 announcement_played = 0;
3387 }
3388
3389 checked = 1;
3390 }
3391 } else {
3392 checked = 0;
3393 }
3394 }
3395
3396 if (user->kicktime && (user->kicktime <= now.tv_sec)) {
3397 if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3398 ret = 0;
3399 } else {
3400 ret = -1;
3401 }
3402 break;
3403 }
3404
3405 to = -1;
3406 if (user->timelimit) {
3407 int minutes = 0, seconds = 0, remain = 0;
3408
3409 to = ast_tvdiff_ms(nexteventts, now);
3410 if (to < 0) {
3411 to = 0;
3412 }
3413 time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
3414 if (time_left_ms < to) {
3415 to = time_left_ms;
3416 }
3417
3418 if (time_left_ms <= 0) {
3419 if (user->end_sound) {
3420 res = ast_streamfile(chan, user->end_sound, ast_channel_language(chan));
3421 res = ast_waitstream(chan, "");
3422 }
3423 if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3424 ret = 0;
3425 } else {
3426 ret = -1;
3427 }
3428 break;
3429 }
3430
3431 if (!to) {
3432 if (time_left_ms >= 5000) {
3433
3434 remain = (time_left_ms + 500) / 1000;
3435 if (remain / 60 >= 1) {
3436 minutes = remain / 60;
3437 seconds = remain % 60;
3438 } else {
3439 seconds = remain;
3440 }
3441
3442 /* force the time left to round up if appropriate */
3443 if (user->warning_sound && user->play_warning) {
3444 if (!strcmp(user->warning_sound, "timeleft")) {
3445
3446 res = ast_streamfile(chan, "vm-youhave", ast_channel_language(chan));
3447 res = ast_waitstream(chan, "");
3448 if (minutes) {
3449 res = ast_say_number(chan, minutes, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3450 res = ast_streamfile(chan, "queue-minutes", ast_channel_language(chan));
3451 res = ast_waitstream(chan, "");
3452 }
3453 if (seconds) {
3454 res = ast_say_number(chan, seconds, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3455 res = ast_streamfile(chan, "queue-seconds", ast_channel_language(chan));
3456 res = ast_waitstream(chan, "");
3457 }
3458 } else {
3459 res = ast_streamfile(chan, user->warning_sound, ast_channel_language(chan));
3460 res = ast_waitstream(chan, "");
3461 }
3462 if (musiconhold) {
3463 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3464 }
3465 }
3466 }
3467 if (user->warning_freq) {
3468 nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
3469 } else {
3470 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
3471 }
3472 }
3473 }
3474
3475 now = ast_tvnow();
3476 if (timeout && now.tv_sec >= timeout) {
3477 if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3478 ret = 0;
3479 } else {
3480 ret = -1;
3481 }
3482 break;
3483 }
3484
3485 /* if we have just exited from the menu, and the user had a channel-driver
3486 volume adjustment, restore it
3487 */
3488 if (!menu_mode && menu_was_active && user->listen.desired && !user->listen.actual) {
3489 set_talk_volume(user, user->listen.desired);
3490 }
3491
3492 menu_was_active = menu_mode;
3493
3494 currentmarked = conf->markedusers;
3495 if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3498 lastmarked == 0) {
3499 if (currentmarked == 1 && conf->users > 1) {
3500 ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3501 if (conf->users - 1 == 1) {
3502 if (!ast_streamfile(chan, "conf-userwilljoin", ast_channel_language(chan))) {
3503 ast_waitstream(chan, "");
3504 }
3505 } else {
3506 if (!ast_streamfile(chan, "conf-userswilljoin", ast_channel_language(chan))) {
3507 ast_waitstream(chan, "");
3508 }
3509 }
3510 }
3511 if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
3512 if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
3513 ast_waitstream(chan, "");
3514 }
3515 }
3516 }
3517
3518 /* Update the struct with the actual confflags */
3519 user->userflags = *confflags;
3520
3521 if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
3522 if (currentmarked == 0) {
3523 if (lastmarked != 0) {
3524 if (!ast_test_flag64(confflags, CONFFLAG_QUIET)) {
3525 if (!ast_streamfile(chan, "conf-leaderhasleft", ast_channel_language(chan))) {
3526 ast_waitstream(chan, "");
3527 }
3528 }
3529 if (ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
3530 if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3531 ret = 0;
3532 }
3533 break;
3534 } else {
3535 dahdic.confmode = DAHDI_CONF_CONF;
3536 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3537 ast_log(LOG_WARNING, "Error setting conference\n");
3538 close(fd);
3539 goto outrun;
3540 }
3541 }
3542 }
3543 if (!musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
3544 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3545 musiconhold = 1;
3546 }
3547 } else if (currentmarked >= 1 && lastmarked == 0) {
3548 /* Marked user entered, so cancel timeout */
3549 timeout = 0;
3550 if (ast_test_flag64(confflags, CONFFLAG_MONITOR)) {
3551 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
3552 } else if (ast_test_flag64(confflags, CONFFLAG_TALKER)) {
3553 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
3554 } else {
3555 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
3556 }
3557 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3558 ast_log(LOG_WARNING, "Error setting conference\n");
3559 close(fd);
3560 goto outrun;
3561 }
3562 if (musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
3563 ast_moh_stop(chan);
3564 musiconhold = 0;
3565 }
3566 if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3567 !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
3568 if (!ast_streamfile(chan, "conf-placeintoconf", ast_channel_language(chan))) {
3569 ast_waitstream(chan, "");
3570 }
3571 conf_play(chan, conf, ENTER);
3572 }
3573 }
3574 }
3575
3576 /* trying to add moh for single person conf */
3577 if (ast_test_flag64(confflags, CONFFLAG_MOH) && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
3578 if (conf->users == 1) {
3579 if (!musiconhold) {
3580 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3581 musiconhold = 1;
3582 }
3583 } else {
3584 if (musiconhold) {
3585 ast_moh_stop(chan);
3586 musiconhold = 0;
3587 }
3588 }
3589 }
3590
3591 /* Leave if the last marked user left */
3592 if (currentmarked == 0 && lastmarked != 0 && ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
3593 if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3594 ret = 0;
3595 } else {
3596 ret = -1;
3597 }
3598 break;
3599 }
3600
3601 /* Throw a TestEvent if a user exit did not cause this user to leave the conference */
3602 if (conf->users != lastusers) {
3603 if (conf->users < lastusers) {
3604 ast_test_suite_event_notify("NOEXIT", "Message: CONFFLAG_MARKEDEXIT\r\nLastUsers: %d\r\nUsers: %d", lastusers, conf->users);
3605 }
3606 lastusers = conf->users;
3607 }
3608
3609 /* Check if my modes have changed */
3610
3611 /* If I should be muted but am still talker, mute me */
3612 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
3613 RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
3614 dahdic.confmode ^= DAHDI_CONF_TALKER;
3615 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3616 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
3617 ret = -1;
3618 break;
3619 }
3620
3621 /* Indicate user is not talking anymore - change him to unmonitored state */
3624 }
3625 meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
3626 }
3627
3628 /* If I should be un-muted but am not talker, un-mute me */
3629 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
3630 RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
3631 dahdic.confmode |= DAHDI_CONF_TALKER;
3632 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3633 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
3634 ret = -1;
3635 break;
3636 }
3637 meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
3638 }
3639
3640 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
3641 (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
3642
3643 RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
3644 talkreq_manager = 1;
3645 meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
3646 }
3647
3648 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
3649 !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
3650 RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
3651 talkreq_manager = 0;
3652 meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
3653 }
3654
3655 /* If user have been hung up, exit the conference */
3656 if (user->adminflags & ADMINFLAG_HANGUP) {
3657 ret = 0;
3658 break;
3659 }
3660
3661 /* If I have been kicked, exit the conference */
3662 if (user->adminflags & ADMINFLAG_KICKME) {
3663 /* You have been kicked. */
3664 if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3665 !ast_streamfile(chan, "conf-kicked", ast_channel_language(chan))) {
3666 ast_waitstream(chan, "");
3667 }
3668 ret = 0;
3669 break;
3670 }
3671
3672 /* Perform a hangup check here since ast_waitfor_nandfds will not always be able to get a channel after a hangup has occurred */
3673 if (ast_check_hangup(chan)) {
3674 break;
3675 }
3676
3677 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
3678
3679 if (c) {
3680 char dtmfstr[2] = "";
3681
3682 if (ast_channel_fd(c, 0) != origfd || (user->dahdichannel && ast_channel_audiohooks(c))) {
3683 if (using_pseudo) {
3684 /* Kill old pseudo */
3685 close(fd);
3686 using_pseudo = 0;
3687 }
3688 ast_debug(1, "Ooh, something swapped out under us, starting over\n");
3689 retrydahdi = (strcasecmp(ast_channel_tech(c)->type, "DAHDI") || ast_channel_audiohooks(c) ? 1 : 0);
3690 user->dahdichannel = !retrydahdi;
3691 goto dahdiretry;
3692 }
3693 if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
3694 f = ast_read_noaudio(c);
3695 } else {
3696 f = ast_read(c);
3697 }
3698 if (!f) {
3699 break;
3700 }
3701 if (f->frametype == AST_FRAME_DTMF) {
3702 dtmfstr[0] = f->subclass.integer;
3703 dtmfstr[1] = '\0';
3704 }
3705
3707 if (user->talk.actual) {
3708 ast_frame_adjust_volume(f, user->talk.actual);
3709 }
3710
3712 if (user->talking == -1) {
3713 user->talking = 0;
3714 }
3715
3716 res = ast_dsp_silence(dsp, f, &totalsilence);
3717 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
3719 }
3720
3721 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
3723 }
3724 }
3725 if (using_pseudo) {
3726 /* Absolutely do _not_ use careful_write here...
3727 it is important that we read data from the channel
3728 as fast as it arrives, and feed it into the conference.
3729 The buffering in the pseudo channel will take care of any
3730 timing differences, unless they are so drastic as to lose
3731 audio frames (in which case carefully writing would only
3732 have delayed the audio even further).
3733 */
3734 /* As it turns out, we do want to use careful write. We just
3735 don't want to block, but we do want to at least *try*
3736 to write out all the samples.
3737 */
3738 if (user->talking || !ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER)) {
3739 careful_write(fd, f->data.ptr, f->datalen, 0);
3740 }
3741 }
3742 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '*') && ast_test_flag64(confflags, CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_mode)) {
3743 if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
3745 }
3746 /* Take out of conference */
3747 if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
3748 ast_log(LOG_WARNING, "Error setting conference\n");
3749 close(fd);
3750 ast_frfree(f);
3751 goto outrun;
3752 }
3753
3754 /* if we are entering the menu, and the user has a channel-driver
3755 volume adjustment, clear it
3756 */
3757 if (!menu_mode && user->talk.desired && !user->talk.actual) {
3759 }
3760
3761 if (musiconhold) {
3762 ast_moh_stop(chan);
3763 } else if (!menu_mode) {
3764 char *menu_to_play;
3765 if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3766 menu_mode = MENU_ADMIN;
3767 menu_to_play = "conf-adminmenu-18";
3768 } else {
3769 menu_mode = MENU_NORMAL;
3770 menu_to_play = "conf-usermenu-162";
3771 }
3772
3773 if (!ast_streamfile(chan, menu_to_play, ast_channel_language(chan))) {
3774 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
3775 ast_stopstream(chan);
3776 } else {
3777 dtmf = 0;
3778 }
3779 } else {
3780 dtmf = f->subclass.integer;
3781 }
3782
3783 if (dtmf > 0) {
3784 meetme_menu(&menu_mode, &dtmf, conf, confflags,
3785 chan, user, recordingtmp, sizeof(recordingtmp), cap_slin);
3786 }
3787
3788 if (musiconhold && !menu_mode) {
3789 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3790 }
3791
3792 /* Put back into conference */
3793 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3794 ast_log(LOG_WARNING, "Error setting conference\n");
3795 close(fd);
3796 ast_frfree(f);
3797 goto outrun;
3798 }
3799
3800 conf_flush(fd, chan);
3801 /*
3802 * Since options using DTMF could absorb DTMF meant for the
3803 * conference menu, we have to check them after the menu.
3804 */
3805 } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
3806 if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
3808 }
3809
3810 if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
3811 ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
3812 ret = 0;
3813 ast_frfree(f);
3814 break;
3815 } else {
3816 ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
3817 }
3818 } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_KEYEXIT) &&
3819 (strchr(exitkeys, f->subclass.integer))) {
3820 pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
3821
3822 if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
3824 }
3825 ret = 0;
3826 ast_frfree(f);
3827 break;
3829 && ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
3831 } else if (f->frametype == AST_FRAME_NULL) {
3832 /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
3833 } else if (f->frametype == AST_FRAME_CONTROL) {
3834 switch (f->subclass.integer) {
3835 case AST_CONTROL_BUSY:
3837 ast_frfree(f);
3838 goto outrun;
3839 break;
3840 default:
3841 ast_debug(1,
3842 "Got ignored control frame on channel %s, f->frametype=%u,f->subclass=%d\n",
3844 }
3845 } else {
3846 ast_debug(1,
3847 "Got unrecognized frame on channel %s, f->frametype=%u,f->subclass=%d\n",
3849 }
3850 ast_frfree(f);
3851 } else if (outfd > -1) {
3852 res = read(outfd, buf, CONF_SIZE);
3853 if (res > 0) {
3854 memset(&fr, 0, sizeof(fr));
3855 fr.frametype = AST_FRAME_VOICE;
3856 fr.subclass.format = ast_format_slin;
3857 fr.datalen = res;
3858 fr.samples = res / 2;
3859 fr.data.ptr = buf;
3860 fr.offset = AST_FRIENDLY_OFFSET;
3861 if (!user->listen.actual &&
3862 (ast_test_flag64(confflags, CONFFLAG_MONITOR) ||
3863 (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
3864 (!user->talking && ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER))
3865 )) {
3866 int idx;
3867 for (idx = 0; idx < AST_FRAME_BITS; idx++) {
3869 break;
3870 }
3871 }
3872 if (idx >= AST_FRAME_BITS) {
3873 goto bailoutandtrynormal;
3874 }
3875 ast_mutex_lock(&conf->listenlock);
3876 if (!conf->transframe[idx]) {
3877 if (conf->origframe) {
3878 if (musiconhold
3879 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)
3880 && !ast_dsp_silence(dsp, conf->origframe, &confsilence)
3881 && confsilence < MEETME_DELAYDETECTTALK) {
3882 ast_moh_stop(chan);
3883 mohtempstopped = 1;
3884 }
3885 if (!conf->transpath[idx]) {
3887 }
3888 if (conf->transpath[idx]) {
3889 conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
3890 if (!conf->transframe[idx]) {
3891 conf->transframe[idx] = &ast_null_frame;
3892 }
3893 }
3894 }
3895 }
3896 if (conf->transframe[idx]) {
3897 if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
3898 can_write(chan, confflags)) {
3899 struct ast_frame *cur;
3900 /* the translator may have returned a list of frames, so
3901 write each one onto the channel
3902 */
3903 for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
3904 if (ast_write(chan, cur)) {
3905 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
3906 break;
3907 }
3908 }
3909 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
3910 mohtempstopped = 0;
3911 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3912 }
3913 }
3914 } else {
3915 ast_mutex_unlock(&conf->listenlock);
3916 goto bailoutandtrynormal;
3917 }
3918 ast_mutex_unlock(&conf->listenlock);
3919 } else {
3920bailoutandtrynormal:
3921 if (musiconhold
3922 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)
3923 && !ast_dsp_silence(dsp, &fr, &confsilence)
3924 && confsilence < MEETME_DELAYDETECTTALK) {
3925 ast_moh_stop(chan);
3926 mohtempstopped = 1;
3927 }
3928 if (user->listen.actual) {
3929 ast_frame_adjust_volume(&fr, user->listen.actual);
3930 }
3931 if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
3932 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
3933 }
3934 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
3935 mohtempstopped = 0;
3936 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3937 }
3938 }
3939 } else {
3940 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
3941 }
3942 }
3943 lastmarked = currentmarked;
3944 }
3945 }
3946
3947 if (musiconhold) {
3948 ast_moh_stop(chan);
3949 }
3950
3951 if (using_pseudo) {
3952 close(fd);
3953 } else {
3954 /* Take out of conference */
3955 dahdic.chan = 0;
3956 dahdic.confno = 0;
3957 dahdic.confmode = 0;
3958 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3959 ast_log(LOG_WARNING, "Error setting conference\n");
3960 }
3961 }
3962
3964
3965 if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
3966 !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3967 conf_play(chan, conf, LEAVE);
3968 }
3969
3971 struct announce_listitem *item;
3972 if (!(item = ao2_alloc(sizeof(*item), NULL)))
3973 goto outrun;
3974 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
3975 ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
3976 item->confchan = conf->chan;
3977 item->confusers = conf->users;
3978 item->announcetype = CONF_HASLEFT;
3980 item->vmrec = 1;
3981 }
3982 ast_mutex_lock(&conf->announcelistlock);
3983 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
3984 ast_cond_signal(&conf->announcelist_addition);
3985 ast_mutex_unlock(&conf->announcelistlock);
3986 } else if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW) && !ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC) && conf->users == 1) {
3987 /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
3988 ast_filedelete(user->namerecloc, NULL);
3989 }
3990
3991 outrun:
3993
3994 if (dsp) {
3995 ast_dsp_free(dsp);
3996 }
3997
3998 if (user->user_no) {
3999 /* Only cleanup users who really joined! */
4000 now = ast_tvnow();
4001
4002 if (sent_event) {
4003 meetme_stasis_generate_msg(conf, chan, user, meetme_leave_type(), NULL);
4004 }
4005
4006 if (setusercount) {
4007 conf->users--;
4008 if (rt_log_members) {
4009 /* Update table */
4010 snprintf(members, sizeof(members), "%d", conf->users);
4012 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
4013 "members", RQ_UINTEGER1, strlen(members),
4014 NULL);
4015 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
4016 }
4017 if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
4018 conf->markedusers--;
4019 }
4020 }
4021 /* Remove ourselves from the container */
4022 ao2_unlink(conf->usercontainer, user);
4023
4024 /* Change any states */
4025 if (!conf->users) {
4027 }
4028
4029 /* This flag is meant to kill a conference with only one participant remaining. */
4030 if (conf->users == 1 && ast_test_flag64(confflags, CONFFLAG_KILL_LAST_MAN_STANDING)) {
4031 ao2_callback(conf->usercontainer, 0, user_set_hangup_cb, NULL);
4032 }
4033
4034 /* Return the number of seconds the user was in the conf */
4035 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
4036 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
4037
4038 /* Return the RealTime bookid for CDR linking */
4039 if (rt_schedule) {
4040 pbx_builtin_setvar_helper(chan, "MEETMEBOOKID", conf->bookid);
4041 }
4042 }
4043 ao2_ref(user, -1);
4045
4046
4047conf_run_cleanup:
4048 ao2_cleanup(cap_slin);
4049
4050 return ret;
4051}
static int rt_log_members
Definition: app_meetme.c:825
menu_modes
Definition: app_meetme.c:2310
#define CONFFLAG_DONT_DENOISE
Definition: app_meetme.c:763
#define CONF_SIZE
Definition: app_meetme.c:695
static void * recordthread(void *args)
Definition: app_meetme.c:5241
#define MEETME_DELAYDETECTENDTALK
Definition: app_meetme.c:674
static void conf_flush(int fd, struct ast_channel *chan)
Definition: app_meetme.c:1944
static int can_write(struct ast_channel *chan, struct ast_flags64 *confflags)
Definition: app_meetme.c:2233
static int set_talk_volume(struct ast_conf_user *user, int volume)
Definition: app_meetme.c:1257
static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
Definition: app_meetme.c:2146
static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
Definition: app_meetme.c:1348
static void meetme_menu(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size, struct ast_format_cap *cap_slin)
Definition: app_meetme.c:2716
static void * announce_thread(void *data)
Definition: app_meetme.c:2176
#define CONFFLAG_KILL_LAST_MAN_STANDING
Definition: app_meetme.c:761
static int user_set_hangup_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2266
#define CONFFLAG_INTROUSER_VMREC
Definition: app_meetme.c:759
#define CONFFLAG_INTROMSG
Definition: app_meetme.c:758
#define MEETME_DELAYDETECTTALK
Definition: app_meetme.c:673
static int audio_buffers
The number of audio buffers to be allocated on pseudo channels when in a conference.
Definition: app_meetme.c:928
static void conf_queue_dtmf(const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
Definition: app_meetme.c:2045
static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
Definition: app_meetme.c:2248
#define DATE_FORMAT
Definition: app_meetme.c:662
static struct ast_json * status_to_json(int on)
Definition: app_meetme.c:1146
static char exitcontext[AST_MAX_CONTEXT]
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static int tmp()
Definition: bt_open.c:389
static const char type[]
Definition: chan_ooh323.c:109
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
Definition: channel.c:2988
#define ast_channel_lock(chan)
Definition: channel.h:2922
const char * ast_channel_context(const struct ast_channel *chan)
struct ast_audiohook_list * ast_channel_audiohooks(const struct ast_channel *chan)
struct ast_format * ast_channel_rawwriteformat(struct ast_channel *chan)
struct ast_frame * ast_read_noaudio(struct ast_channel *chan)
Reads a frame, returning AST_FRAME_NULL frame if audio.
Definition: channel.c:4267
#define AST_MAX_CONTEXT
Definition: channel.h:135
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7422
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4277
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1574
#define ast_channel_unlock(chan)
Definition: channel.h:2923
#define AST_MAX_EXTENSION
Definition: channel.h:134
@ AST_DEVSTATE_CACHABLE
Definition: devicestate.h:70
@ AST_DEVSTATE_NOT_CACHABLE
Definition: devicestate.h:69
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:510
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
@ THRESHOLD_SILENCE
Definition: dsp.h:73
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
Definition: dsp.c:1488
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:2009
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2206
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
@ AST_FORMAT_CMP_EQUAL
Definition: format.h:36
int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence_ms, const char *path)
Record a file based on input from a channel. Use default accept and cancel DTMF. This function will p...
Definition: main/app.c:2144
int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
Allow to record message and have a review option.
Definition: main/app.c:2636
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3549
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3659
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3506
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
uint64_t ast_format_compatibility_format2bitfield(const struct ast_format *format)
Convert a format structure to its respective bitfield.
#define AST_FRAME_DTMF
#define AST_OPTION_TONE_VERIFY
int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
Adjusts the volume of the audio samples contained in a frame.
Definition: main/frame.c:787
#define AST_FRIENDLY_OFFSET
Offset into a frame's data buffer.
@ AST_FRAME_NULL
@ AST_FRAME_DTMF_END
@ AST_FRAME_DTMF_BEGIN
@ AST_FRAME_VOICE
@ AST_FRAME_CONTROL
@ AST_CONTROL_BUSY
@ AST_CONTROL_CONGESTION
struct ast_frame ast_null_frame
Definition: main/frame.c:79
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
Definition: localtime.c:2357
char * ast_strptime(const char *s, const char *format, struct ast_tm *tm)
Special version of strptime(3) which places the answer in the common structure ast_tm....
Definition: localtime.c:2550
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7776
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:154
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4175
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8781
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8235
ast_app: A registered application
Definition: pbx_app.c:45
Main Channel structure associated with a channel.
Definition: dsp.c:407
struct ast_format * format
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
Abstract JSON element (object, array, string, int, ...).
static struct test_val c
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:282
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:117
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2297
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
struct ast_frame * ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume)
translates one or more frames Apply an input frame into the translator and receive zero or one output...
Definition: translate.c:566
struct ast_trans_pvt * ast_translator_build_path(struct ast_format *dest, struct ast_format *source)
Builds a translator path Build a path (possibly NULL) from source to dest.
Definition: translate.c:486
#define ast_clear_flag64(p, flag)
Definition: utils.h:134
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: utils.c:2479
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:597

References ADMINFLAG_HANGUP, ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, announce_thread(), ao2_alloc, ao2_callback, ao2_cleanup, ao2_link, ao2_lock, ao2_ref, ao2_unlink, ao2_unlock, ast_channel_audiohooks(), ast_channel_context(), ast_channel_fd(), ast_channel_language(), ast_channel_lock, ast_channel_name(), ast_channel_rawwriteformat(), ast_channel_setoption(), ast_channel_tech(), ast_channel_uniqueid(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag64, ast_cond_signal, ast_config_AST_SPOOL_DIR, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, ast_copy_string(), ast_debug, AST_DEVICE_INUSE, AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), AST_DEVSTATE_NOT_CACHABLE, AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_silence(), ast_exists_extension(), ast_filedelete(), ast_fileexists(), ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_compatibility_format2bitfield(), ast_format_slin, 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_func_write(), ast_goto_if_exists(), ast_hangup(), ast_indicate(), ast_json_unref(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_NEXT, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log, AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mkdir(), ast_mktime(), ast_moh_stop(), ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_null_frame, AST_OPTION_TONE_VERIFY, ast_play_and_record(), ast_pthread_create_background, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_read(), ast_read_noaudio(), ast_realtime_require_field(), ast_record_review(), ast_request(), ast_safe_sleep(), ast_samp2tv(), ast_say_digits(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_test_flag64, ast_test_suite_event_notify, ast_translate(), ast_translator_build_path(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvsub(), ast_tvzero(), ast_update_realtime(), ast_variables_destroy(), ast_verb, ast_verbose(), ast_waitfor_nandfds(), ast_waitstream(), ast_write(), audio_buffers, buf, c, can_write(), careful_write(), conf_flush(), CONF_HASJOIN, CONF_HASLEFT, conf_play(), conf_queue_dtmf(), CONF_SIZE, conf_start_moh(), CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_DONT_DENOISE, CONFFLAG_DURATION_LIMIT, CONFFLAG_DURATION_STOP, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROMSG, CONFFLAG_INTROUSER, CONFFLAG_INTROUSER_VMREC, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_KEYEXIT, CONFFLAG_KICK_CONTINUE, CONFFLAG_KILL_LAST_MAN_STANDING, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_NO_AUDIO_UNTIL_UP, CONFFLAG_NOONLYPERSON, CONFFLAG_OPTIMIZETALKER, CONFFLAG_PASS_DTMF, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_STARMENU, CONFFLAG_STARTMUTED, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, voicemailpwcheck::context, ast_frame::data, ast_frame::datalen, DATE_FORMAT, ENTER, errno, exitcontext, ast_frame_subclass::format, ast_frame::frametype, ast_frame_subclass::integer, item, LEAVE, LOG_WARNING, voicemailpwcheck::mailbox, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, meetme_menu(), meetme_stasis_generate_msg(), MENU_ADMIN, MENU_DISABLED, MENU_NORMAL, NULL, OBJ_NODATA, ast_frame::offset, OPT_ARG_DURATION_LIMIT, OPT_ARG_DURATION_STOP, OPT_ARG_EXITKEYS, OPT_ARG_INTROMSG, OPT_ARG_INTROUSER_VMREC, OPT_ARG_MOH_CLASS, OPT_ARG_WAITMARKED, PATH_MAX, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_frame::ptr, RAII_VAR, recordthread(), reset_volumes(), RQ_UINTEGER1, RQ_UINTEGER2, RQ_UINTEGER3, RQ_UINTEGER4, rt_log_members, rt_schedule, ast_frame::samples, set_talk_volume(), set_user_talking(), status_to_json(), strsep(), ast_frame::subclass, THRESHOLD_SILENCE, tmp(), type, user_max_cmp(), user_set_hangup_cb(), and var.

Referenced by conf_exec().

◆ conf_start_moh()

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

Definition at line 2146 of file app_meetme.c.

2147{
2148 char *original_moh;
2149
2150 ast_channel_lock(chan);
2151 original_moh = ast_strdupa(ast_channel_musicclass(chan));
2152 ast_channel_musicclass_set(chan, musicclass);
2153 ast_channel_unlock(chan);
2154
2155 ast_moh_start(chan, original_moh, NULL);
2156
2157 ast_channel_lock(chan);
2158 ast_channel_musicclass_set(chan, original_moh);
2159 ast_channel_unlock(chan);
2160}
const char * ast_channel_musicclass(const struct ast_channel *chan)
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7766

References ast_channel_lock, ast_channel_musicclass(), ast_channel_unlock, ast_moh_start(), ast_strdupa, and NULL.

Referenced by conf_run().

◆ count_exec()

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

The MeetmeCount application.

Definition at line 4344 of file app_meetme.c.

4345{
4346 int res = 0;
4347 struct ast_conference *conf;
4348 int count;
4349 char *localdata;
4350 char val[80] = "0";
4353 AST_APP_ARG(varname);
4354 );
4355
4356 if (ast_strlen_zero(data)) {
4357 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
4358 return -1;
4359 }
4360
4361 localdata = ast_strdupa(data);
4362
4363 AST_STANDARD_APP_ARGS(args, localdata);
4364
4365 conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
4366
4367 if (conf) {
4368 count = conf->users;
4370 conf = NULL;
4371 } else
4372 count = 0;
4373
4374 if (!ast_strlen_zero(args.varname)) {
4375 /* have var so load it and exit */
4376 snprintf(val, sizeof(val), "%d", count);
4378 } else {
4381 }
4382 res = ast_say_number(chan, count, "", ast_channel_language(chan), (char *) NULL); /* Needs gender */
4383 }
4384
4385 return res;
4386}
Definition: ast_expr2.c:325

References args, ast_answer(), AST_APP_ARG, ast_channel_language(), AST_DECLARE_APP_ARGS, ast_log, ast_say_number(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_conference::chan, ast_conference::confno, dispose_conf(), find_conf(), LOG_WARNING, NULL, and pbx_builtin_setvar_helper().

Referenced by load_module().

◆ dispose_conf()

static int dispose_conf ( struct ast_conference conf)
static

Decrement reference counts, as incremented by find_conf()

Definition at line 2065 of file app_meetme.c.

2066{
2067 int res = 0;
2068 int confno_int = 0;
2069
2071 if (ast_atomic_dec_and_test(&conf->refcount)) {
2072 /* Take the conference room number out of an inuse state */
2073 if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
2074 conf_map[confno_int] = 0;
2075 }
2076 conf_free(conf);
2077 res = 1;
2078 }
2080
2081 return res;
2082}
static int conf_free(struct ast_conference *conf)
Remove the conference from the list and free it.
Definition: app_meetme.c:1976
int ast_atomic_dec_and_test(volatile int *p)
decrement *p by 1 and return true if the variable has reached 0.
Definition: lock.h:767

References ast_atomic_dec_and_test(), AST_LIST_LOCK, AST_LIST_UNLOCK, conf_free(), and conf_map.

Referenced by admin_exec(), conf_exec(), and count_exec().

◆ filename_parse()

static void filename_parse ( char *  filename,
char *  buffer 
)
static

Definition at line 5222 of file app_meetme.c.

5223{
5224 char *slash;
5225 if (ast_strlen_zero(filename)) {
5226 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
5227 } else if (filename[0] != '/') {
5228 snprintf(buffer, PATH_MAX, "%s/meetme/%s", ast_config_AST_SPOOL_DIR, filename);
5229 } else {
5230 ast_copy_string(buffer, filename, PATH_MAX);
5231 }
5232
5233 slash = buffer;
5234 if ((slash = strrchr(slash, '/'))) {
5235 *slash = '\0';
5236 ast_mkdir(buffer, 0777);
5237 *slash = '/';
5238 }
5239}

References ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_log, ast_mkdir(), ast_strlen_zero(), LOG_WARNING, and PATH_MAX.

Referenced by recordthread().

◆ find_conf()

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_flags64 confflags 
)
static

Definition at line 4240 of file app_meetme.c.

4242{
4243 struct ast_config *cfg;
4244 struct ast_variable *var;
4245 struct ast_flags config_flags = { 0 };
4246 struct ast_conference *cnf;
4247
4252 );
4253
4254 /* Check first in the conference list */
4255 ast_debug(1, "The requested confno is '%s'?\n", confno);
4257 AST_LIST_TRAVERSE(&confs, cnf, list) {
4258 ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
4259 if (!strcmp(confno, cnf->confno))
4260 break;
4261 }
4262 if (cnf) {
4263 cnf->refcount += refcount;
4264 }
4266
4267 if (!cnf) {
4268 if (dynamic) {
4269 /* No need to parse meetme.conf */
4270 ast_debug(1, "Building dynamic conference '%s'\n", confno);
4271 if (dynamic_pin) {
4272 if (dynamic_pin[0] == 'q') {
4273 /* Query the user to enter a PIN */
4274 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
4275 return NULL;
4276 }
4277 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan, NULL);
4278 } else {
4279 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan, NULL);
4280 }
4281 } else {
4282 /* Check the config */
4283 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
4284 if (!cfg) {
4285 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
4286 return NULL;
4287 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
4288 ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
4289 return NULL;
4290 }
4291
4292 for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
4293 char parse[MAX_SETTINGS];
4294
4295 if (strcasecmp(var->name, "conf"))
4296 continue;
4297
4298 ast_copy_string(parse, var->value, sizeof(parse));
4299
4301 ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
4302 if (!strcasecmp(args.confno, confno)) {
4303 /* Bingo it's a valid conference */
4304 cnf = build_conf(args.confno,
4305 S_OR(args.pin, ""),
4306 S_OR(args.pinadmin, ""),
4307 make, dynamic, refcount, chan, NULL);
4308 break;
4309 }
4310 }
4311 if (!var) {
4312 ast_log(LOG_WARNING, "%s isn't a valid conference\n", confno);
4313 }
4314 ast_config_destroy(cfg);
4315 }
4316 } else if (dynamic_pin) {
4317 /* Correct for the user selecting 'D' instead of 'd' to have
4318 someone join into a conference that has already been created
4319 with a pin. */
4320 if (dynamic_pin[0] == 'q') {
4321 dynamic_pin[0] = '\0';
4322 }
4323 }
4324
4325 if (cnf) {
4326 if (confflags && !cnf->chan &&
4327 !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4329 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
4331 }
4332
4333 if (confflags && !cnf->chan &&
4335 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
4337 }
4338 }
4339
4340 return cnf;
4341}
static struct ast_conference * build_conf(const char *confno, const char *pin, const char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan, struct ast_test *test)
Find or create a conference.
Definition: app_meetme.c:1428
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80

References args, AST_APP_ARG, ast_app_getdata(), ast_clear_flag64, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, AST_STANDARD_APP_ARGS, ast_test_flag64, ast_variable_browse(), build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSER_VMREC, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, ast_conference::confno, ast_conference::list, LOG_ERROR, LOG_WARNING, MAX_SETTINGS, NULL, ast_conference::pin, ast_conference::pinadmin, ast_conference::refcount, S_OR, and var.

Referenced by conf_exec(), and count_exec().

◆ find_conf_realtime()

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_flags64 confflags,
int *  too_early,
char **  optargs 
)
static

Definition at line 4053 of file app_meetme.c.

4055{
4056 struct ast_variable *var, *origvar;
4057 struct ast_conference *cnf;
4058
4059 *too_early = 0;
4060
4061 /* Check first in the conference list */
4063 AST_LIST_TRAVERSE(&confs, cnf, list) {
4064 if (!strcmp(confno, cnf->confno)) {
4065 break;
4066 }
4067 }
4068 if (cnf) {
4069 cnf->refcount += refcount;
4070 }
4072
4073 if (!cnf) {
4074 char *pin = NULL, *pinadmin = NULL; /* For temp use */
4075 int maxusers = 0;
4076 struct timeval now;
4077 char recordingfilename[256] = "";
4078 char recordingformat[11] = "";
4079 char currenttime[32] = "";
4080 char eatime[32] = "";
4081 char bookid[51] = "";
4082 char recordingtmp[AST_MAX_EXTENSION * 2] = "";
4083 char useropts[OPTIONS_LEN + 1] = ""; /* Used for RealTime conferences */
4084 char adminopts[OPTIONS_LEN + 1] = "";
4085 struct ast_tm tm, etm;
4086 struct timeval endtime = { .tv_sec = 0 };
4087 const char *var2;
4088
4089 if (rt_schedule) {
4090 now = ast_tvnow();
4091
4092 ast_localtime(&now, &tm, NULL);
4093 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
4094
4095 ast_debug(1, "Looking for conference %s that starts after %s\n", confno, currenttime);
4096
4097 var = ast_load_realtime("meetme", "confno",
4098 confno, "starttime <= ", currenttime, "endtime >= ",
4099 currenttime, NULL);
4100
4101 if (!var && fuzzystart) {
4102 now = ast_tvnow();
4103 now.tv_sec += fuzzystart;
4104
4105 ast_localtime(&now, &tm, NULL);
4106 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
4107 var = ast_load_realtime("meetme", "confno",
4108 confno, "starttime <= ", currenttime, "endtime >= ",
4109 currenttime, NULL);
4110 }
4111
4112 if (!var && earlyalert) {
4113 now = ast_tvnow();
4114 now.tv_sec += earlyalert;
4115 ast_localtime(&now, &etm, NULL);
4116 ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
4117 var = ast_load_realtime("meetme", "confno",
4118 confno, "starttime <= ", eatime, "endtime >= ",
4119 currenttime, NULL);
4120 if (var) {
4121 *too_early = 1;
4122 }
4123 }
4124
4125 } else {
4126 var = ast_load_realtime("meetme", "confno", confno, NULL);
4127 }
4128
4129 if (!var) {
4130 return NULL;
4131 }
4132
4133 if (rt_schedule && *too_early) {
4134 /* Announce that the caller is early and exit */
4135 if (!ast_streamfile(chan, "conf-has-not-started", ast_channel_language(chan))) {
4136 ast_waitstream(chan, "");
4137 }
4139 return NULL;
4140 }
4141
4142 for (origvar = var; var; var = var->next) {
4143 if (!strcasecmp(var->name, "pin")) {
4144 pin = ast_strdupa(var->value);
4145 } else if (!strcasecmp(var->name, "adminpin")) {
4146 pinadmin = ast_strdupa(var->value);
4147 } else if (!strcasecmp(var->name, "bookId")) {
4148 ast_copy_string(bookid, var->value, sizeof(bookid));
4149 } else if (!strcasecmp(var->name, "opts")) {
4150 ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
4151 } else if (!strcasecmp(var->name, "maxusers")) {
4152 maxusers = atoi(var->value);
4153 } else if (!strcasecmp(var->name, "adminopts")) {
4154 ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
4155 } else if (!strcasecmp(var->name, "recordingfilename")) {
4156 ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
4157 } else if (!strcasecmp(var->name, "recordingformat")) {
4158 ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
4159 } else if (!strcasecmp(var->name, "endtime")) {
4160 struct ast_tm endtime_tm;
4161 ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
4162 endtime = ast_mktime(&endtime_tm, NULL);
4163 }
4164 }
4165
4166 ast_variables_destroy(origvar);
4167
4168 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan, NULL);
4169
4170 if (cnf) {
4171 struct ast_flags64 tmp_flags;
4172
4173 cnf->maxusers = maxusers;
4174 cnf->endalert = endalert;
4175 cnf->endtime = endtime.tv_sec;
4176 cnf->useropts = ast_strdup(useropts);
4177 cnf->adminopts = ast_strdup(adminopts);
4178 cnf->bookid = ast_strdup(bookid);
4179 if (!ast_strlen_zero(recordingfilename)) {
4180 cnf->recordingfilename = ast_strdup(recordingfilename);
4181 }
4182 if (!ast_strlen_zero(recordingformat)) {
4183 cnf->recordingformat = ast_strdup(recordingformat);
4184 }
4185
4186 /* Parse the other options into confflags -- need to do this in two
4187 * steps, because the parse_options routine zeroes the buffer. */
4188 ast_app_parse_options64(meetme_opts, &tmp_flags, optargs, useropts);
4189 ast_copy_flags64(confflags, &tmp_flags, tmp_flags.flags);
4190
4191 if (strchr(cnf->useropts, 'r')) {
4192 if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */
4193 ast_channel_lock(chan);
4194 if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
4196 cnf->recordingfilename = ast_strdup(var2);
4197 }
4198 ast_channel_unlock(chan);
4200 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, ast_channel_uniqueid(chan));
4202 cnf->recordingfilename = ast_strdup(recordingtmp);
4203 }
4204 }
4205 if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */
4206 ast_channel_lock(chan);
4207 if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
4209 cnf->recordingformat = ast_strdup(var2);
4210 }
4211 ast_channel_unlock(chan);
4212 if (ast_strlen_zero(cnf->recordingformat)) {
4214 cnf->recordingformat = ast_strdup("wav");
4215 }
4216 }
4217 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
4218 }
4219 }
4220 }
4221
4222 if (cnf) {
4223 if (confflags->flags && !cnf->chan &&
4224 !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4226 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
4228 }
4229
4230 if (confflags && !cnf->chan &&
4232 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
4234 }
4235 }
4236
4237 return cnf;
4238}
static int endalert
Definition: app_meetme.c:821
#define OPTIONS_LEN
Definition: app_meetme.c:829
static int earlyalert
Definition: app_meetme.c:820
static int fuzzystart
Definition: app_meetme.c:819
const char * bookid
Definition: app_meetme.c:879
uint64_t flags
Definition: utils.h:205
#define ast_copy_flags64(dest, src, flagz)
Definition: utils.h:141

References ast_conference::adminopts, ast_app_parse_options64(), ast_channel_language(), ast_channel_lock, ast_channel_uniqueid(), ast_channel_unlock, ast_clear_flag64, ast_copy_flags64, ast_copy_string(), ast_debug, ast_free, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_load_realtime(), ast_localtime(), ast_log, AST_MAX_EXTENSION, ast_mktime(), ast_strdup, ast_strdupa, ast_streamfile(), ast_strftime(), ast_strlen_zero(), ast_strptime(), ast_test_flag64, ast_tvnow(), ast_variables_destroy(), ast_verb, ast_waitstream(), ast_conference::bookid, build_conf(), ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_INTROUSER_VMREC, CONFFLAG_INTROUSERNOREVIEW, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, ast_conference::confno, DATE_FORMAT, earlyalert, endalert, ast_conference::endalert, ast_conference::endtime, ast_flags64::flags, fuzzystart, ast_conference::list, LOG_WARNING, ast_conference::maxusers, meetme_opts, NULL, OPTIONS_LEN, pbx_builtin_getvar_helper(), ast_conference::pin, ast_conference::pinadmin, ast_conference::recordingfilename, ast_conference::recordingformat, ast_conference::refcount, rt_schedule, ast_conference::useropts, and var.

Referenced by conf_exec().

◆ find_user()

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

Definition at line 4714 of file app_meetme.c.

4715{
4716 struct ast_conf_user *user = NULL;
4717 int cid;
4718
4719 if (conf && callerident && sscanf(callerident, "%30d", &cid) == 1) {
4720 user = ao2_find(conf->usercontainer, &cid, 0);
4721 /* reference decremented later in admin_exec */
4722 return user;
4723 }
4724 return NULL;
4725}

References ao2_find, NULL, and user.

Referenced by admin_exec().

◆ get_announce_filename()

static const char * get_announce_filename ( enum announcetypes  type)
static

Definition at line 2162 of file app_meetme.c.

2163{
2164 switch (type) {
2165 case CONF_HASLEFT:
2166 return "conf-hasleft";
2167 break;
2168 case CONF_HASJOIN:
2169 return "conf-hasjoin";
2170 break;
2171 default:
2172 return "";
2173 }
2174}

References CONF_HASJOIN, CONF_HASLEFT, and type.

Referenced by announce_thread().

◆ istalking()

static const char * istalking ( int  x)
static

Definition at line 1220 of file app_meetme.c.

1221{
1222 if (x > 0)
1223 return "(talking)";
1224 else if (x < 0)
1225 return "(unmonitored)";
1226 else
1227 return "(not talking)";
1228}

Referenced by meetme_show_cmd().

◆ load_config()

static int load_config ( int  reload)
static

Definition at line 5487 of file app_meetme.c.

5488{
5490 return 0;
5491}
static void load_config_meetme(int reload)
Definition: app_meetme.c:5348
static int reload(void)
Definition: app_meetme.c:5553

References load_config_meetme(), and reload().

Referenced by load_module(), and reload().

◆ load_config_meetme()

static void load_config_meetme ( int  reload)
static

Definition at line 5348 of file app_meetme.c.

5349{
5350 struct ast_config *cfg;
5351 struct ast_flags config_flags = { 0 };
5352 const char *val;
5353
5354 if (!reload) {
5356 }
5357
5358 if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
5359 return;
5360 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
5361 ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
5362 return;
5363 }
5364
5365 if (reload) {
5367 }
5368
5369 if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
5370 if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
5371 ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
5373 } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
5374 ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
5375 DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
5377 }
5379 ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
5380 }
5381
5382 if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
5384 if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
5386 if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
5387 if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
5388 ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
5389 fuzzystart = 0;
5390 }
5391 }
5392 if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
5393 if ((sscanf(val, "%30d", &earlyalert) != 1)) {
5394 ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
5395 earlyalert = 0;
5396 }
5397 }
5398 if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
5399 if ((sscanf(val, "%30d", &endalert) != 1)) {
5400 ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
5401 endalert = 0;
5402 }
5403 }
5404 if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
5405 if ((sscanf(val, "%30d", &extendby) != 1)) {
5406 ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
5407 extendby = 0;
5408 }
5409 }
5410
5411 ast_config_destroy(cfg);
5412}
static void meetme_set_defaults(void)
Definition: app_meetme.c:5332
static int extendby
Definition: app_meetme.c:822
#define DEFAULT_AUDIO_BUFFERS
Definition: app_meetme.c:659
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199

References ast_config_destroy(), ast_config_load, ast_log, ast_true(), ast_variable_retrieve(), audio_buffers, CONFIG_FILE_NAME, CONFIG_STATUS_FILEINVALID, DEFAULT_AUDIO_BUFFERS, earlyalert, endalert, extendby, fuzzystart, LOG_ERROR, LOG_NOTICE, LOG_WARNING, meetme_set_defaults(), reload(), rt_log_members, and rt_schedule.

Referenced by load_config().

◆ load_module()

static int load_module ( void  )
static

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 5527 of file app_meetme.c.

5528{
5529 int res = 0;
5530
5531 res |= load_config(0);
5532
5533 res |= meetme_stasis_init();
5534
5544
5545 res |= ast_devstate_prov_add("Meetme", meetmestate);
5546
5548 ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
5549
5550 return res;
5551}
static int action_meetmeunmute(struct mansession *s, const struct message *m)
Definition: app_meetme.c:5076
static struct ast_custom_function meetme_info_acf
Definition: app_meetme.c:5482
static int count_exec(struct ast_channel *chan, const char *data)
The MeetmeCount application.
Definition: app_meetme.c:4344
static struct ast_cli_entry cli_meetme[]
Definition: app_meetme.c:1937
static const char *const app
Definition: app_meetme.c:812
static const char *const app4
Definition: app_meetme.c:815
static const char *const app2
Definition: app_meetme.c:813
static int channel_admin_exec(struct ast_channel *chan, const char *data)
The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command)
Definition: app_meetme.c:4950
static const char *const app3
Definition: app_meetme.c:814
static enum ast_device_state meetmestate(const char *data)
Callback for devicestate providers.
Definition: app_meetme.c:5310
static int action_meetmelist(struct mansession *s, const struct message *m)
Definition: app_meetme.c:5081
static int admin_exec(struct ast_channel *chan, const char *data)
The MeetMeAdmin application.
Definition: app_meetme.c:4777
static int action_meetmemute(struct mansession *s, const struct message *m)
Definition: app_meetme.c:5071
static int meetme_stasis_init(void)
Definition: app_meetme.c:979
static int conf_exec(struct ast_channel *chan, const char *data)
The meetme() application.
Definition: app_meetme.c:4389
static int load_config(int reload)
Definition: app_meetme.c:5487
static int action_meetmelistrooms(struct mansession *s, const struct message *m)
Definition: app_meetme.c:5153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
Add device state provider.
Definition: devicestate.c:391
#define EVENT_FLAG_REPORTING
Definition: manager.h:84
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
#define EVENT_FLAG_CALL
Definition: manager.h:76
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558

References action_meetmelist(), action_meetmelistrooms(), action_meetmemute(), action_meetmeunmute(), admin_exec(), app, app2, app3, app4, ARRAY_LEN, ast_cli_register_multiple, ast_custom_function_register, ast_devstate_prov_add(), ast_manager_register_xml, ast_realtime_require_field(), ast_register_application_xml, channel_admin_exec(), cli_meetme, conf_exec(), count_exec(), EVENT_FLAG_CALL, EVENT_FLAG_REPORTING, load_config(), meetme_info_acf, meetme_stasis_init(), meetmestate(), NULL, RQ_UINTEGER1, and RQ_UINTEGER2.

◆ meetme_cmd_helper()

static char * meetme_cmd_helper ( struct ast_cli_args a)
static

Definition at line 1817 of file app_meetme.c.

1818{
1819 /* Process the command */
1820 struct ast_str *cmdline;
1821
1822 /* Max confno length */
1823 if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
1824 return CLI_FAILURE;
1825 }
1826
1827 ast_str_set(&cmdline, 0, "%s", a->argv[2]); /* Argv 2: conference number */
1828 if (strcasestr(a->argv[1], "lock")) {
1829 if (strcasecmp(a->argv[1], "lock") == 0) {
1830 /* Lock */
1831 ast_str_append(&cmdline, 0, ",L");
1832 } else {
1833 /* Unlock */
1834 ast_str_append(&cmdline, 0, ",l");
1835 }
1836 } else if (strcasestr(a->argv[1], "mute")) {
1837 if (strcasecmp(a->argv[1], "mute") == 0) {
1838 /* Mute */
1839 if (strcasecmp(a->argv[3], "all") == 0) {
1840 ast_str_append(&cmdline, 0, ",N");
1841 } else {
1842 ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);
1843 }
1844 } else {
1845 /* Unmute */
1846 if (strcasecmp(a->argv[3], "all") == 0) {
1847 ast_str_append(&cmdline, 0, ",n");
1848 } else {
1849 ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
1850 }
1851 }
1852 } else if (strcasecmp(a->argv[1], "kick") == 0) {
1853 if (strcasecmp(a->argv[3], "all") == 0) {
1854 /* Kick all */
1855 ast_str_append(&cmdline, 0, ",K");
1856 } else {
1857 /* Kick a single user */
1858 ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
1859 }
1860 } else {
1861 /*
1862 * Should never get here because it is already filtered by the
1863 * callers.
1864 */
1865 ast_free(cmdline);
1866 return CLI_SHOWUSAGE;
1867 }
1868
1869 ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
1870
1871 admin_exec(NULL, ast_str_buffer(cmdline));
1872 ast_free(cmdline);
1873
1874 return CLI_SUCCESS;
1875}
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
#define CLI_FAILURE
Definition: cli.h:46
char * strcasestr(const char *, const char *)
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
Support for dynamic strings.
Definition: strings.h:623
static struct test_val a

References a, admin_exec(), ast_debug, ast_free, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_set(), CLI_FAILURE, CLI_SHOWUSAGE, CLI_SUCCESS, MAX_CONFNUM, NULL, and strcasestr().

Referenced by meetme_kick_cmd(), meetme_lock_cmd(), and meetme_mute_cmd().

◆ meetme_kick_cmd()

static char * meetme_kick_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1897 of file app_meetme.c.

1898{
1899 switch (cmd) {
1900 case CLI_INIT:
1901 e->command = "meetme kick";
1902 e->usage =
1903 "Usage: meetme kick <confno> all|<userno>\n"
1904 " Kick a conference or a user in a conference.\n";
1905 return NULL;
1906 case CLI_GENERATE:
1907 return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
1908 }
1909
1910 if (a->argc != 4) {
1911 return CLI_SHOWUSAGE;
1912 }
1913
1914 return meetme_cmd_helper(a);
1915}
static char * meetme_cmd_helper(struct ast_cli_args *a)
Definition: app_meetme.c:1817
static char * complete_meetmecmd_mute_kick(const char *line, const char *word, int pos, int state)
Definition: app_meetme.c:1588
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177

References a, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_meetmecmd_mute_kick(), meetme_cmd_helper(), NULL, and ast_cli_entry::usage.

◆ meetme_lock_cmd()

static char * meetme_lock_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1877 of file app_meetme.c.

1878{
1879 switch (cmd) {
1880 case CLI_INIT:
1881 e->command = "meetme {lock|unlock}";
1882 e->usage =
1883 "Usage: meetme lock|unlock <confno>\n"
1884 " Lock or unlock a conference to new users.\n";
1885 return NULL;
1886 case CLI_GENERATE:
1887 return complete_meetmecmd_lock(a->word, a->pos, a->n);
1888 }
1889
1890 if (a->argc != 3) {
1891 return CLI_SHOWUSAGE;
1892 }
1893
1894 return meetme_cmd_helper(a);
1895}
static char * complete_meetmecmd_lock(const char *word, int pos, int state)
Definition: app_meetme.c:1628

References a, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_meetmecmd_lock(), meetme_cmd_helper(), NULL, and ast_cli_entry::usage.

◆ meetme_menu()

static void meetme_menu ( enum menu_modes menu_mode,
int *  dtmf,
struct ast_conference conf,
struct ast_flags64 confflags,
struct ast_channel chan,
struct ast_conf_user user,
char *  recordingtmp,
int  recordingtmp_size,
struct ast_format_cap cap_slin 
)
static

Definition at line 2716 of file app_meetme.c.

2720{
2721 switch (*menu_mode) {
2722 case MENU_DISABLED:
2723 break;
2724 case MENU_NORMAL:
2725 meetme_menu_normal(menu_mode, dtmf, conf, confflags, chan, user);
2726 break;
2727 case MENU_ADMIN:
2728 meetme_menu_admin(menu_mode, dtmf, conf, confflags, chan, user);
2729 /* Admin Menu is capable of branching into another menu, in which case it will reset dtmf and change the menu mode. */
2730 if (*menu_mode != MENU_ADMIN_EXTENDED || (*dtmf <= 0)) {
2731 break;
2732 }
2734 meetme_menu_admin_extended(menu_mode, dtmf, conf, confflags, chan, user,
2735 recordingtmp, recordingtmp_size, cap_slin);
2736 break;
2737 }
2738}
static void meetme_menu_normal(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
Definition: app_meetme.c:2327
static void meetme_menu_admin(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
Definition: app_meetme.c:2407
static void meetme_menu_admin_extended(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size, struct ast_format_cap *cap_slin)
Definition: app_meetme.c:2528

References meetme_menu_admin(), meetme_menu_admin_extended(), meetme_menu_normal(), MENU_ADMIN, MENU_ADMIN_EXTENDED, MENU_DISABLED, and MENU_NORMAL.

Referenced by conf_run().

◆ meetme_menu_admin()

static void meetme_menu_admin ( enum menu_modes menu_mode,
int *  dtmf,
struct ast_conference conf,
struct ast_flags64 confflags,
struct ast_channel chan,
struct ast_conf_user user 
)
static

Definition at line 2407 of file app_meetme.c.

2408{
2409 switch(*dtmf) {
2410 case '1': /* Un/Mute */
2411 *menu_mode = MENU_DISABLED;
2412 /* for admin, change both admin and use flags */
2413 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
2414 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2415 } else {
2416 user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2417 }
2418
2419 if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2420 if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
2421 ast_waitstream(chan, "");
2422 }
2423 } else {
2424 if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
2425 ast_waitstream(chan, "");
2426 }
2427 }
2428 break;
2429
2430 case '2': /* Un/Lock the Conference */
2431 *menu_mode = MENU_DISABLED;
2432 if (conf->locked) {
2433 conf->locked = 0;
2434 if (!ast_streamfile(chan, "conf-unlockednow", ast_channel_language(chan))) {
2435 ast_waitstream(chan, "");
2436 }
2437 } else {
2438 conf->locked = 1;
2439 if (!ast_streamfile(chan, "conf-lockednow", ast_channel_language(chan))) {
2440 ast_waitstream(chan, "");
2441 }
2442 }
2443 break;
2444
2445 case '3': /* Eject last user */
2446 {
2447 struct ast_conf_user *usr = NULL;
2448 int max_no = 0;
2449 ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
2450 *menu_mode = MENU_DISABLED;
2451 usr = ao2_find(conf->usercontainer, &max_no, 0);
2453 if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2454 ast_waitstream(chan, "");
2455 }
2456 } else {
2458 }
2459 ao2_ref(usr, -1);
2461 break;
2462 }
2463
2464 case '4':
2466 break;
2467
2468 case '5':
2469 /* Extend RT conference */
2470 if (rt_schedule) {
2471 if (!rt_extend_conf(conf->confno)) {
2472 if (!ast_streamfile(chan, "conf-extended", ast_channel_language(chan))) {
2473 ast_waitstream(chan, "");
2474 }
2475 } else {
2476 if (!ast_streamfile(chan, "conf-nonextended", ast_channel_language(chan))) {
2477 ast_waitstream(chan, "");
2478 }
2479 }
2481 }
2482 *menu_mode = MENU_DISABLED;
2483 break;
2484
2485 case '6':
2487 break;
2488
2489 case '7':
2491 break;
2492
2493 case '8':
2494 if (!ast_streamfile(chan, "conf-adminmenu-menu8", ast_channel_language(chan))) {
2495 /* If the user provides DTMF while playing the sound, we want to drop right into the extended menu function with new DTMF once we get out of here. */
2498 }
2499 *menu_mode = MENU_ADMIN_EXTENDED;
2500 break;
2501
2502 case '9':
2504 break;
2505 default:
2506 *menu_mode = MENU_DISABLED;
2507 /* Play an error message! */
2508 if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2509 ast_waitstream(chan, "");
2510 }
2511 break;
2512 }
2513
2514}
struct ast_flags64 userflags
Definition: app_meetme.c:906

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ast_conf_user::adminflags, ao2_callback, ao2_find, ao2_ref, ast_channel_language(), ast_channel_name(), AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_test_flag64, ast_waitstream(), ast_conf_user::chan, CONFFLAG_ADMIN, CONFFLAG_MONITOR, MENU_ADMIN_EXTENDED, MENU_DISABLED, NULL, OBJ_NODATA, rt_extend_conf(), rt_schedule, tweak_listen_volume(), tweak_talk_volume(), user_max_cmp(), ast_conf_user::userflags, VOL_DOWN, and VOL_UP.

Referenced by meetme_menu().

◆ meetme_menu_admin_extended()

static void meetme_menu_admin_extended ( enum menu_modes menu_mode,
int *  dtmf,
struct ast_conference conf,
struct ast_flags64 confflags,
struct ast_channel chan,
struct ast_conf_user user,
char *  recordingtmp,
int  recordingtmp_size,
struct ast_format_cap cap_slin 
)
static

Definition at line 2528 of file app_meetme.c.

2532{
2533 int keepplaying;
2534 int playednamerec;
2535 int res;
2536 struct ao2_iterator user_iter;
2537 struct ast_conf_user *usr = NULL;
2538
2539 switch(*dtmf) {
2540 case '1': /* *81 Roll call */
2541 keepplaying = 1;
2542 playednamerec = 0;
2543 if (conf->users == 1) {
2544 if (keepplaying && !ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
2547 if (res > 0) {
2548 keepplaying = 0;
2549 }
2550 }
2551 } else if (conf->users == 2) {
2552 if (keepplaying && !ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
2555 if (res > 0) {
2556 keepplaying = 0;
2557 }
2558 }
2559 } else {
2560 if (keepplaying && !ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
2563 if (res > 0) {
2564 keepplaying = 0;
2565 }
2566 }
2567 if (keepplaying) {
2568 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
2570 if (res > 0) {
2571 keepplaying = 0;
2572 }
2573 }
2574 if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
2577 if (res > 0) {
2578 keepplaying = 0;
2579 }
2580 }
2581 }
2582 user_iter = ao2_iterator_init(conf->usercontainer, 0);
2583 while((usr = ao2_iterator_next(&user_iter))) {
2584 if (ast_fileexists(usr->namerecloc, NULL, NULL)) {
2585 if (keepplaying && !ast_streamfile(chan, usr->namerecloc, ast_channel_language(chan))) {
2588 if (res > 0) {
2589 keepplaying = 0;
2590 }
2591 }
2592 playednamerec = 1;
2593 }
2594 ao2_ref(usr, -1);
2595 }
2596 ao2_iterator_destroy(&user_iter);
2597 if (keepplaying && playednamerec && !ast_streamfile(chan, "conf-roll-callcomplete", ast_channel_language(chan))) {
2600 if (res > 0) {
2601 keepplaying = 0;
2602 }
2603 }
2604
2605 *menu_mode = MENU_DISABLED;
2606 break;
2607
2608 case '2': /* *82 Eject all non-admins */
2609 if (conf->users == 1) {
2610 if(!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2611 ast_waitstream(chan, "");
2612 }
2613 } else {
2615 }
2617 *menu_mode = MENU_DISABLED;
2618 break;
2619
2620 case '3': /* *83 (Admin) mute/unmute all non-admins */
2621 if(conf->gmuted) {
2622 conf->gmuted = 0;
2624 if (!ast_streamfile(chan, "conf-now-unmuted", ast_channel_language(chan))) {
2625 ast_waitstream(chan, "");
2626 }
2627 } else {
2628 conf->gmuted = 1;
2630 if (!ast_streamfile(chan, "conf-now-muted", ast_channel_language(chan))) {
2631 ast_waitstream(chan, "");
2632 }
2633 }
2635 *menu_mode = MENU_DISABLED;
2636 break;
2637
2638 case '4': /* *84 Record conference */
2639 if (conf->recording != MEETME_RECORD_ACTIVE) {
2641 if (!conf->recordingfilename) {
2642 const char *var;
2644 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
2645 conf->recordingfilename = ast_strdup(var);
2646 }
2647 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
2648 conf->recordingformat = ast_strdup(var);
2649 }
2651 if (!conf->recordingfilename) {
2652 snprintf(recordingtmp, recordingtmp_size, "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
2653 conf->recordingfilename = ast_strdup(recordingtmp);
2654 }
2655 if (!conf->recordingformat) {
2656 conf->recordingformat = ast_strdup("wav");
2657 }
2658 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
2659 conf->confno, conf->recordingfilename, conf->recordingformat);
2660 }
2661
2662 ast_mutex_lock(&conf->recordthreadlock);
2663 if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
2664 struct dahdi_confinfo dahdic;
2665
2668 dahdic.chan = 0;
2669 dahdic.confno = conf->dahdiconf;
2670 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
2671 if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
2672 ast_log(LOG_WARNING, "Error starting listen channel\n");
2673 ast_hangup(conf->lchan);
2674 conf->lchan = NULL;
2675 } else {
2677 }
2678 }
2679 ast_mutex_unlock(&conf->recordthreadlock);
2680 if (!ast_streamfile(chan, "conf-now-recording", ast_channel_language(chan))) {
2681 ast_waitstream(chan, "");
2682 }
2683 }
2684
2685 ast_stopstream(chan);
2686 *menu_mode = MENU_DISABLED;
2687 break;
2688
2689 case '8': /* *88 Exit the menu and return to the conference... without an error message */
2690 ast_stopstream(chan);
2691 *menu_mode = MENU_DISABLED;
2692 break;
2693
2694 default:
2695 if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2696 ast_waitstream(chan, "");
2697 }
2698 ast_stopstream(chan);
2699 *menu_mode = MENU_DISABLED;
2700 break;
2701 }
2702}
char namerecloc[PATH_MAX]
Definition: app_meetme.c:912
#define ast_set_flag64(p, flag)
Definition: utils.h:127

References ao2_callback, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_fd(), ast_channel_language(), ast_channel_lock, ast_channel_uniqueid(), ast_channel_unlock, AST_DIGIT_ANY, ast_fileexists(), ast_format_slin, ast_hangup(), ast_log, ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_detached_background, AST_PTHREADT_NULL, ast_request(), ast_say_number(), ast_set_flag64, ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdup, ast_streamfile(), ast_test_flag64, ast_verb, ast_waitstream(), ast_conf_user::chan, CONFFLAG_RECORDCONF, LOG_WARNING, MEETME_RECORD_ACTIVE, MENU_DISABLED, ast_conf_user::namerecloc, NULL, OBJ_NODATA, pbx_builtin_getvar_helper(), recordthread(), user_set_kickme_cb(), user_set_muted_cb(), user_set_unmuted_cb(), and var.

Referenced by meetme_menu().

◆ meetme_menu_normal()

static void meetme_menu_normal ( enum menu_modes menu_mode,
int *  dtmf,
struct ast_conference conf,
struct ast_flags64 confflags,
struct ast_channel chan,
struct ast_conf_user user 
)
static

Definition at line 2327 of file app_meetme.c.

2328{
2329 switch (*dtmf) {
2330 case '1': /* Un/Mute */
2331 *menu_mode = MENU_DISABLED;
2332
2333 /* user can only toggle the self-muted state */
2334 user->adminflags ^= ADMINFLAG_SELFMUTED;
2335
2336 /* they can't override the admin mute state */
2337 if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2338 if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
2339 ast_waitstream(chan, "");
2340 }
2341 } else {
2342 if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
2343 ast_waitstream(chan, "");
2344 }
2345 }
2346 break;
2347
2348 case '2':
2349 *menu_mode = MENU_DISABLED;
2350 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
2351 user->adminflags |= ADMINFLAG_T_REQUEST;
2352 }
2353
2354 if (user->adminflags & ADMINFLAG_T_REQUEST) {
2355 if (!ast_streamfile(chan, "beep", ast_channel_language(chan))) {
2356 ast_waitstream(chan, "");
2357 }
2358 }
2359 break;
2360
2361 case '4':
2363 break;
2364 case '5':
2365 /* Extend RT conference */
2366 if (rt_schedule) {
2367 rt_extend_conf(conf->confno);
2368 }
2369 *menu_mode = MENU_DISABLED;
2370 break;
2371
2372 case '6':
2374 break;
2375
2376 case '7':
2378 break;
2379
2380 case '8':
2381 *menu_mode = MENU_DISABLED;
2382 break;
2383
2384 case '9':
2386 break;
2387
2388 default:
2389 *menu_mode = MENU_DISABLED;
2390 if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2391 ast_waitstream(chan, "");
2392 }
2393 break;
2394 }
2395}

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_channel_language(), ast_streamfile(), ast_test_flag64, ast_waitstream(), ast_conf_user::chan, CONFFLAG_MONITOR, MENU_DISABLED, rt_extend_conf(), rt_schedule, tweak_listen_volume(), tweak_talk_volume(), VOL_DOWN, and VOL_UP.

Referenced by meetme_menu().

◆ meetme_mute_cmd()

static char * meetme_mute_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1917 of file app_meetme.c.

1918{
1919 switch (cmd) {
1920 case CLI_INIT:
1921 e->command = "meetme {mute|unmute}";
1922 e->usage =
1923 "Usage: meetme mute|unmute <confno> all|<userno>\n"
1924 " Mute or unmute a conference or a user in a conference.\n";
1925 return NULL;
1926 case CLI_GENERATE:
1927 return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
1928 }
1929
1930 if (a->argc != 4) {
1931 return CLI_SHOWUSAGE;
1932 }
1933
1934 return meetme_cmd_helper(a);
1935}

References a, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, ast_cli_entry::command, complete_meetmecmd_mute_kick(), meetme_cmd_helper(), NULL, and ast_cli_entry::usage.

◆ meetme_set_defaults()

static void meetme_set_defaults ( void  )
static

Definition at line 5332 of file app_meetme.c.

5333{
5334 /* Scheduling support is off by default */
5335 rt_schedule = 0;
5336 fuzzystart = 0;
5337 earlyalert = 0;
5338 endalert = 0;
5339 extendby = 0;
5340
5341 /* Logging of participants defaults to ON for compatibility reasons */
5342 rt_log_members = 1;
5343
5344 /* Set default number of buffers to be allocated. */
5346}

References audio_buffers, DEFAULT_AUDIO_BUFFERS, earlyalert, endalert, extendby, fuzzystart, rt_log_members, and rt_schedule.

Referenced by load_config_meetme().

◆ meetme_show_cmd()

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

Definition at line 1675 of file app_meetme.c.

1676{
1677 /* Process the command */
1678 struct ast_conf_user *user;
1679 struct ast_conference *cnf;
1680 int hr, min, sec;
1681 int total = 0;
1682 time_t now;
1683#define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n"
1684#define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
1685
1686 switch (cmd) {
1687 case CLI_INIT:
1688 e->command = "meetme list";
1689 e->usage =
1690 "Usage: meetme list [<confno>] [" STR_CONCISE "]\n"
1691 " List all conferences or a specific conference.\n";
1692 return NULL;
1693 case CLI_GENERATE:
1694 return complete_meetmecmd_list(a->line, a->word, a->pos, a->n);
1695 }
1696
1697 if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], STR_CONCISE))) {
1698 /* List all the conferences */
1699 int concise = (a->argc == 3);
1700 struct ast_str *marked_users;
1701
1702 if (!(marked_users = ast_str_create(30))) {
1703 return CLI_FAILURE;
1704 }
1705
1706 now = time(NULL);
1708 if (AST_LIST_EMPTY(&confs)) {
1709 if (!concise) {
1710 ast_cli(a->fd, "No active MeetMe conferences.\n");
1711 }
1713 ast_free(marked_users);
1714 return CLI_SUCCESS;
1715 }
1716 if (!concise) {
1717 ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
1718 }
1719 AST_LIST_TRAVERSE(&confs, cnf, list) {
1720 hr = (now - cnf->start) / 3600;
1721 min = ((now - cnf->start) % 3600) / 60;
1722 sec = (now - cnf->start) % 60;
1723 if (!concise) {
1724 if (cnf->markedusers == 0) {
1725 ast_str_set(&marked_users, 0, "N/A ");
1726 } else {
1727 ast_str_set(&marked_users, 0, "%4.4d", cnf->markedusers);
1728 }
1729 ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users,
1730 ast_str_buffer(marked_users), hr, min, sec,
1731 cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
1732 } else {
1733 ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
1734 cnf->confno,
1735 cnf->users,
1736 cnf->markedusers,
1737 hr, min, sec,
1738 cnf->isdynamic,
1739 cnf->locked);
1740 }
1741
1742 total += cnf->users;
1743 }
1745 if (!concise) {
1746 ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
1747 }
1748 ast_free(marked_users);
1749 return CLI_SUCCESS;
1750 }
1751 if (a->argc == 3 || (a->argc == 4 && !strcasecmp(a->argv[3], STR_CONCISE))) {
1752 struct ao2_iterator user_iter;
1753 int concise = (a->argc == 4);
1754
1755 /* List all the users in a conference */
1756 if (AST_LIST_EMPTY(&confs)) {
1757 if (!concise) {
1758 ast_cli(a->fd, "No active MeetMe conferences.\n");
1759 }
1760 return CLI_SUCCESS;
1761 }
1762 /* Find the right conference */
1764 AST_LIST_TRAVERSE(&confs, cnf, list) {
1765 if (strcmp(cnf->confno, a->argv[2]) == 0) {
1766 break;
1767 }
1768 }
1769 if (!cnf) {
1770 if (!concise)
1771 ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
1773 return CLI_SUCCESS;
1774 }
1775 /* Show all the users */
1776 time(&now);
1777 user_iter = ao2_iterator_init(cnf->usercontainer, 0);
1778 while((user = ao2_iterator_next(&user_iter))) {
1779 hr = (now - user->jointime) / 3600;
1780 min = ((now - user->jointime) % 3600) / 60;
1781 sec = (now - user->jointime) % 60;
1782 if (!concise) {
1783 ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
1784 user->user_no,
1786 S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
1787 ast_channel_name(user->chan),
1788 ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "(Admin)" : "",
1789 ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "(Listen only)" : "",
1790 user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
1791 user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
1792 istalking(user->talking), hr, min, sec);
1793 } else {
1794 ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
1795 user->user_no,
1798 ast_channel_name(user->chan),
1799 ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "1" : "",
1800 ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "1" : "",
1801 user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
1802 user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
1803 user->talking, hr, min, sec);
1804 }
1805 ao2_ref(user, -1);
1806 }
1807 ao2_iterator_destroy(&user_iter);
1808 if (!concise) {
1809 ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
1810 }
1812 return CLI_SUCCESS;
1813 }
1814 return CLI_SHOWUSAGE;
1815}
static const char * istalking(int x)
Definition: app_meetme.c:1220
static char * complete_meetmecmd_list(const char *line, const char *word, int pos, int state)
Definition: app_meetme.c:1636
#define MC_DATA_FORMAT
#define MC_HEADER_FORMAT
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6

References a, ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_caller(), ast_channel_name(), ast_cli(), ast_free, AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_str_buffer(), ast_str_create, ast_str_set(), ast_test_flag64, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_meetmecmd_list(), CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, ast_party_caller::id, ast_conference::isdynamic, istalking(), ast_conference::locked, ast_conference::markedusers, MC_DATA_FORMAT, MC_HEADER_FORMAT, min, ast_party_id::name, NULL, ast_party_id::number, S_COR, ast_conference::start, ast_party_name::str, ast_party_number::str, STR_CONCISE, total, ast_cli_entry::usage, user, ast_conference::usercontainer, ast_conference::users, ast_party_name::valid, and ast_party_number::valid.

◆ meetme_stasis_cb()

static void meetme_stasis_cb ( void *  data,
struct stasis_subscription sub,
struct stasis_message message 
)
static

Definition at line 1048 of file app_meetme.c.

1050{
1051 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1052 struct stasis_message_type *message_type;
1053 const char *event;
1054 const char *conference_num;
1055 const char *status;
1056 struct ast_json *json_cur;
1057 RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
1058 RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
1059
1060 if (!channel_blob) {
1061 ast_assert(0);
1062 return;
1063 }
1064
1065 message_type = stasis_message_type(message);
1066
1067 if (!message_type) {
1068 ast_assert(0);
1069 return;
1070 }
1071
1072 if (message_type == meetme_join_type()) {
1073 event = "MeetmeJoin";
1074 } else if (message_type == meetme_leave_type()) {
1075 event = "MeetmeLeave";
1076 } else if (message_type == meetme_end_type()) {
1077 event = "MeetmeEnd";
1078 } else if (message_type == meetme_mute_type()) {
1079 event = "MeetmeMute";
1080 } else if (message_type == meetme_talking_type()) {
1081 event = "MeetmeTalking";
1082 } else if (message_type == meetme_talk_request_type()) {
1083 event = "MeetmeTalkRequest";
1084 } else {
1085 ast_assert(0);
1086 return;
1087 }
1088
1089 if (!event) {
1090 ast_assert(0);
1091 return;
1092 }
1093
1094 conference_num = ast_json_string_get(ast_json_object_get(channel_blob->blob, "Meetme"));
1095 if (!conference_num) {
1096 ast_assert(0);
1097 return;
1098 }
1099
1100 status = ast_json_string_get(ast_json_object_get(channel_blob->blob, "status"));
1101 if (status) {
1102 ast_str_append_event_header(&extra_text, "Status", status);
1103 }
1104
1105 if (channel_blob->snapshot) {
1106 channel_text = ast_manager_build_channel_state_string(channel_blob->snapshot);
1107 }
1108
1109 if ((json_cur = ast_json_object_get(channel_blob->blob, "user"))) {
1110 int user_number = ast_json_integer_get(json_cur);
1111 RAII_VAR(struct ast_str *, user_prop_str, ast_str_create(32), ast_free);
1112 if (!user_prop_str) {
1113 return;
1114 }
1115
1116 ast_str_set(&user_prop_str, 0, "%d", user_number);
1117 ast_str_append_event_header(&extra_text, "User", ast_str_buffer(user_prop_str));
1118
1119 if ((json_cur = ast_json_object_get(channel_blob->blob, "duration"))) {
1120 int duration = ast_json_integer_get(json_cur);
1121 ast_str_set(&user_prop_str, 0, "%d", duration);
1122 ast_str_append_event_header(&extra_text, "Duration", ast_str_buffer(user_prop_str));
1123 }
1124
1125 json_cur = NULL;
1126 }
1127
1129 "Meetme: %s\r\n"
1130 "%s"
1131 "%s",
1132 conference_num,
1133 channel_text ? ast_str_buffer(channel_text) : "",
1134 extra_text ? ast_str_buffer(extra_text) : "");
1135}
jack_status_t status
Definition: app_jack.c:146
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:332
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:253
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
int ast_str_append_event_header(struct ast_str **fields_string, const char *header, const char *value)
append an event header to an ast string
Definition: manager.c:10542
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
Definition: astman.c:222
#define ast_assert(a)
Definition: utils.h:739

References ast_assert, ast_free, ast_json_integer_get(), ast_json_object_get(), ast_json_string_get(), ast_manager_build_channel_state_string(), ast_str_append_event_header(), ast_str_buffer(), ast_str_create, ast_str_set(), ast_channel_blob::blob, EVENT_FLAG_CALL, manager_event, NULL, RAII_VAR, ast_channel_blob::snapshot, stasis_message_data(), stasis_message_type(), and status.

Referenced by meetme_stasis_init().

◆ meetme_stasis_cleanup()

static void meetme_stasis_cleanup ( void  )
static

Definition at line 964 of file app_meetme.c.

965{
969 }
970
971 STASIS_MESSAGE_TYPE_CLEANUP(meetme_join_type);
972 STASIS_MESSAGE_TYPE_CLEANUP(meetme_leave_type);
973 STASIS_MESSAGE_TYPE_CLEANUP(meetme_end_type);
974 STASIS_MESSAGE_TYPE_CLEANUP(meetme_mute_type);
975 STASIS_MESSAGE_TYPE_CLEANUP(meetme_talking_type);
976 STASIS_MESSAGE_TYPE_CLEANUP(meetme_talk_request_type);
977}
static struct stasis_message_router * meetme_event_message_router
Definition: app_meetme.c:952
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
void stasis_message_router_unsubscribe(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic.

References meetme_event_message_router, NULL, stasis_message_router_unsubscribe(), and STASIS_MESSAGE_TYPE_CLEANUP.

Referenced by meetme_stasis_init(), and unload_module().

◆ meetme_stasis_generate_msg()

static void meetme_stasis_generate_msg ( struct ast_conference meetme_conference,
struct ast_channel chan,
struct ast_conf_user user,
struct stasis_message_type message_type,
struct ast_json extras 
)
static

Definition at line 1165 of file app_meetme.c.

1167{
1168 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
1169 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1170
1171 json_object = ast_json_pack("{s: s}",
1172 "Meetme", meetme_conference->confno);
1173
1174 if (!json_object) {
1175 return;
1176 }
1177
1178 if (extras) {
1179 ast_json_object_update(json_object, extras);
1180 }
1181
1182 if (user) {
1183 struct timeval now = ast_tvnow();
1184 long duration = (long)(now.tv_sec - user->jointime);
1185 struct ast_json *json_user;
1186 struct ast_json *json_user_duration;
1187
1188 json_user = ast_json_integer_create(user->user_no);
1189 if (!json_user || ast_json_object_set(json_object, "user", json_user)) {
1190 return;
1191 }
1192
1193 if (duration > 0) {
1194 json_user_duration = ast_json_integer_create(duration);
1195 if (!json_user_duration
1196 || ast_json_object_set(json_object, "duration", json_user_duration)) {
1197 return;
1198 }
1199 }
1200 }
1201
1202 if (chan) {
1203 ast_channel_lock(chan);
1204 }
1205 msg = ast_channel_blob_create(chan, message_type, json_object);
1206 if (chan) {
1207 ast_channel_unlock(chan);
1208 }
1209
1210 if (!msg) {
1211 return;
1212 }
1213
1215}
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
struct stasis_message * ast_channel_blob_create(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Creates a ast_channel_blob message.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
struct ast_json * ast_json_integer_create(intmax_t value)
Create a JSON integer.
Definition: json.c:327
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:414
int ast_json_object_update(struct ast_json *object, struct ast_json *other)
Update object with all of the fields of other.
Definition: json.c:426
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1511

References ao2_cleanup, ast_channel_blob_create(), ast_channel_lock, ast_channel_topic(), ast_channel_unlock, ast_json_integer_create(), ast_json_object_set(), ast_json_object_update(), ast_json_pack(), ast_json_unref(), ast_tvnow(), ast_conference::confno, NULL, RAII_VAR, and stasis_publish().

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

◆ meetme_stasis_init()

static int meetme_stasis_init ( void  )
static

Definition at line 979 of file app_meetme.c.

980{
981
982 STASIS_MESSAGE_TYPE_INIT(meetme_join_type);
983 STASIS_MESSAGE_TYPE_INIT(meetme_leave_type);
984 STASIS_MESSAGE_TYPE_INIT(meetme_end_type);
985 STASIS_MESSAGE_TYPE_INIT(meetme_mute_type);
986 STASIS_MESSAGE_TYPE_INIT(meetme_talking_type);
987 STASIS_MESSAGE_TYPE_INIT(meetme_talk_request_type);
988
991
994 return -1;
995 }
996
998 meetme_join_type(),
1000 NULL)) {
1002 return -1;
1003 }
1004
1006 meetme_leave_type(),
1008 NULL)) {
1010 return -1;
1011 }
1012
1014 meetme_end_type(),
1016 NULL)) {
1018 return -1;
1019 }
1020
1022 meetme_mute_type(),
1024 NULL)) {
1026 return -1;
1027 }
1028
1030 meetme_talking_type(),
1032 NULL)) {
1034 return -1;
1035 }
1036
1038 meetme_talk_request_type(),
1040 NULL)) {
1042 return -1;
1043 }
1044
1045 return 0;
1046}
static void meetme_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: app_meetme.c:1048
static void meetme_stasis_cleanup(void)
Definition: app_meetme.c:964
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
#define stasis_message_router_create(topic)
Create a new message router object.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.

References ast_channel_topic_all(), meetme_event_message_router, meetme_stasis_cb(), meetme_stasis_cleanup(), NULL, stasis_message_router_add(), stasis_message_router_create, and STASIS_MESSAGE_TYPE_INIT.

Referenced by load_module().

◆ meetmemute()

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

Definition at line 5011 of file app_meetme.c.

5012{
5013 struct ast_conference *conf;
5014 struct ast_conf_user *user;
5015 const char *confid = astman_get_header(m, "Meetme");
5016 char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
5017 int userno;
5018
5019 if (ast_strlen_zero(confid)) {
5020 astman_send_error(s, m, "Meetme conference not specified");
5021 return 0;
5022 }
5023
5024 if (ast_strlen_zero(userid)) {
5025 astman_send_error(s, m, "Meetme user number not specified");
5026 return 0;
5027 }
5028
5029 userno = strtoul(userid, &userid, 10);
5030
5031 if (*userid) {
5032 astman_send_error(s, m, "Invalid user number");
5033 return 0;
5034 }
5035
5036 /* Look in the conference list */
5039 if (!strcmp(confid, conf->confno))
5040 break;
5041 }
5042
5043 if (!conf) {
5045 astman_send_error(s, m, "Meetme conference does not exist");
5046 return 0;
5047 }
5048
5049 user = ao2_find(conf->usercontainer, &userno, 0);
5050
5051 if (!user) {
5053 astman_send_error(s, m, "User number not found");
5054 return 0;
5055 }
5056
5057 if (mute)
5058 user->adminflags |= ADMINFLAG_MUTED; /* request user muting */
5059 else
5060 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
5061
5063
5064 ast_log(LOG_NOTICE, "Requested to %smute conf %s user %d userchan %s uniqueid %s\n", mute ? "" : "un", conf->confno, user->user_no, ast_channel_name(user->chan), ast_channel_uniqueid(user->chan));
5065
5066 ao2_ref(user, -1);
5067 astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
5068 return 0;
5069}
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3421

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ao2_find, ao2_ref, ast_channel_name(), ast_channel_uniqueid(), 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::list, LOG_NOTICE, and user.

Referenced by action_meetmemute(), and action_meetmeunmute().

◆ meetmestate()

static enum ast_device_state meetmestate ( const char *  data)
static

Callback for devicestate providers.

Definition at line 5310 of file app_meetme.c.

5311{
5312 struct ast_conference *conf;
5313
5314 /* Find conference */
5317 if (!strcmp(data, conf->confno))
5318 break;
5319 }
5321 if (!conf)
5322 return AST_DEVICE_INVALID;
5323
5324
5325 /* SKREP to fill */
5326 if (!conf->users)
5327 return AST_DEVICE_NOT_INUSE;
5328
5329 return AST_DEVICE_INUSE;
5330}
@ AST_DEVICE_INVALID
Definition: devicestate.h:57

References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and ast_conference::list.

Referenced by load_module().

◆ recordthread()

static void * recordthread ( void *  args)
static

Definition at line 5241 of file app_meetme.c.

5242{
5243 struct ast_conference *cnf = args;
5244 struct ast_frame *f = NULL;
5245 int flags;
5246 struct ast_filestream *s = NULL;
5247 int res = 0;
5248 int x;
5249 const char *oldrecordingfilename = NULL;
5250 char filename_buffer[PATH_MAX];
5251
5252 if (!cnf || !cnf->lchan) {
5253 pthread_exit(0);
5254 }
5255
5256 filename_buffer[0] = '\0';
5257 filename_parse(cnf->recordingfilename, filename_buffer);
5258
5259 ast_stopstream(cnf->lchan);
5260 flags = O_CREAT | O_TRUNC | O_WRONLY;
5261
5262
5264 while (ast_waitfor(cnf->lchan, -1) > -1) {
5265 if (cnf->recording == MEETME_RECORD_TERMINATE) {
5268 break;
5269 }
5270 if (!s && !(ast_strlen_zero(filename_buffer)) && (filename_buffer != oldrecordingfilename)) {
5271 s = ast_writefile(filename_buffer, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
5272 oldrecordingfilename = filename_buffer;
5273 }
5274
5275 f = ast_read(cnf->lchan);
5276 if (!f) {
5277 res = -1;
5278 break;
5279 }
5280 if (f->frametype == AST_FRAME_VOICE) {
5282 for (x = 0; x < AST_FRAME_BITS; x++) {
5283 /* Free any translations that have occured */
5284 if (cnf->transframe[x]) {
5285 ast_frfree(cnf->transframe[x]);
5286 cnf->transframe[x] = NULL;
5287 }
5288 }
5289 if (cnf->origframe)
5290 ast_frfree(cnf->origframe);
5291 cnf->origframe = ast_frdup(f);
5293 if (s)
5294 res = ast_writestream(s, f);
5295 if (res) {
5296 ast_frfree(f);
5297 break;
5298 }
5299 }
5300 ast_frfree(f);
5301 }
5303 if (s)
5304 ast_closestream(s);
5305
5306 pthread_exit(0);
5307}
static void filename_parse(char *filename, char *buffer)
Definition: app_meetme.c:5222
#define AST_FILE_MODE
Definition: asterisk.h:32
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:244
struct ast_filestream * ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts writing a file.
Definition: file.c:1423
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1111
#define ast_frdup(fr)
Copies a frame.
struct ast_frame * transframe[32]
Definition: app_meetme.c:880
struct ast_channel * lchan
Definition: app_meetme.c:855
struct ast_frame * origframe
Definition: app_meetme.c:881
enum recording_state recording
Definition: app_meetme.c:864
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:101
unsigned int flags

References args, ast_closestream(), AST_FILE_MODE, AST_FRAME_BITS, AST_FRAME_VOICE, ast_frdup, ast_frfree, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_read(), ast_stopstream(), ast_strlen_zero(), ast_waitfor(), ast_writefile(), ast_writestream(), ast_filestream::f, filename_parse(), ast_frame::flags, ast_filestream::flags, ast_conference::lchan, ast_conference::listenlock, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, NULL, ast_conference::origframe, PATH_MAX, ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, and ast_conference::transframe.

Referenced by conf_run(), and meetme_menu_admin_extended().

◆ reload()

static int reload ( void  )
static

Definition at line 5553 of file app_meetme.c.

5554{
5555 ast_unload_realtime("meetme");
5556 return load_config(1);
5557}
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3576

References ast_unload_realtime(), and load_config().

Referenced by load_config(), and load_config_meetme().

◆ reset_volumes()

static void reset_volumes ( struct ast_conf_user user)
static

Definition at line 1340 of file app_meetme.c.

1341{
1342 signed char zero_volume = 0;
1343
1344 ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1345 ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
1346}
#define AST_OPTION_RXGAIN
#define AST_OPTION_TXGAIN

References ast_channel_setoption(), AST_OPTION_RXGAIN, and AST_OPTION_TXGAIN.

Referenced by admin_exec(), conf_run(), and user_reset_vol_cb().

◆ rt_extend_conf()

static int rt_extend_conf ( const char *  confno)
static

Definition at line 2084 of file app_meetme.c.

2085{
2086 char currenttime[32];
2087 char endtime[32];
2088 struct timeval now;
2089 struct ast_tm tm;
2090 struct ast_variable *var, *orig_var;
2091 char bookid[51];
2092
2093 if (!extendby) {
2094 return 0;
2095 }
2096
2097 now = ast_tvnow();
2098
2099 ast_localtime(&now, &tm, NULL);
2100 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2101
2102 var = ast_load_realtime("meetme", "confno",
2103 confno, "startTime<= ", currenttime,
2104 "endtime>= ", currenttime, NULL);
2105
2106 orig_var = var;
2107
2108 /* Identify the specific RealTime conference */
2109 while (var) {
2110 if (!strcasecmp(var->name, "bookid")) {
2111 ast_copy_string(bookid, var->value, sizeof(bookid));
2112 }
2113 if (!strcasecmp(var->name, "endtime")) {
2114 ast_copy_string(endtime, var->value, sizeof(endtime));
2115 }
2116
2117 var = var->next;
2118 }
2119 ast_variables_destroy(orig_var);
2120
2121 ast_strptime(endtime, DATE_FORMAT, &tm);
2122 now = ast_mktime(&tm, NULL);
2123
2124 now.tv_sec += extendby;
2125
2126 ast_localtime(&now, &tm, NULL);
2127 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2128 strcat(currenttime, "0"); /* Seconds needs to be 00 */
2129
2130 var = ast_load_realtime("meetme", "confno",
2131 confno, "startTime<= ", currenttime,
2132 "endtime>= ", currenttime, NULL);
2133
2134 /* If there is no conflict with extending the conference, update the DB */
2135 if (!var) {
2136 ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
2137 ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
2138 return 0;
2139
2140 }
2141
2143 return -1;
2144}

References ast_copy_string(), ast_debug, ast_load_realtime(), ast_localtime(), ast_mktime(), ast_strftime(), ast_strptime(), ast_tvnow(), ast_update_realtime(), ast_variables_destroy(), DATE_FORMAT, extendby, NULL, and var.

Referenced by admin_exec(), meetme_menu_admin(), and meetme_menu_normal().

◆ send_talking_event()

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

Definition at line 2242 of file app_meetme.c.

2243{
2244 RAII_VAR(struct ast_json *, status_blob, status_to_json(talking), ast_json_unref);
2245 meetme_stasis_generate_msg(conf, chan, user, meetme_talking_type(), status_blob);
2246}

References ast_json_unref(), ast_conference::chan, meetme_stasis_generate_msg(), RAII_VAR, and status_to_json().

Referenced by set_user_talking().

◆ set_listen_volume()

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

Definition at line 1269 of file app_meetme.c.

1270{
1271 char gain_adjust;
1272
1273 /* attempt to make the adjustment in the channel driver;
1274 if successful, don't adjust in the frame reading routine
1275 */
1276 gain_adjust = gain_map[volume + 5];
1277
1278 return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
1279}
static const char gain_map[]
Map 'volume' levels from -5 through +5 into decibel (dB) settings for channel drivers.
Definition: app_meetme.c:937

References ast_channel_setoption(), AST_OPTION_TXGAIN, and gain_map.

Referenced by tweak_listen_volume().

◆ set_talk_volume()

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

Definition at line 1257 of file app_meetme.c.

1258{
1259 char gain_adjust;
1260
1261 /* attempt to make the adjustment in the channel driver;
1262 if successful, don't adjust in the frame reading routine
1263 */
1264 gain_adjust = gain_map[volume + 5];
1265
1266 return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
1267}

References ast_channel_setoption(), AST_OPTION_RXGAIN, and gain_map.

Referenced by conf_run(), and tweak_talk_volume().

◆ set_user_talking()

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

Definition at line 2248 of file app_meetme.c.

2249{
2250 int last_talking = user->talking;
2251 if (last_talking == talking)
2252 return;
2253
2254 user->talking = talking;
2255
2256 if (monitor) {
2257 /* Check if talking state changed. Take care of -1 which means unmonitored */
2258 int was_talking = (last_talking > 0);
2259 int now_talking = (talking > 0);
2260 if (was_talking != now_talking) {
2261 send_talking_event(chan, conf, user, now_talking);
2262 }
2263 }
2264}
static void send_talking_event(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
Definition: app_meetme.c:2242

References ast_conference::chan, and send_talking_event().

Referenced by conf_run().

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [1/6]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( meetme_end_type  )

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [2/6]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( meetme_join_type  )

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [3/6]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( meetme_leave_type  )

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [4/6]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( meetme_mute_type  )

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [5/6]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( meetme_talk_request_type  )

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [6/6]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( meetme_talking_type  )

◆ status_to_json()

static struct ast_json * status_to_json ( int  on)
static

Definition at line 1146 of file app_meetme.c.

1147{
1148 struct ast_json *json_object = ast_json_pack("{s: s}",
1149 "status", on ? "on" : "off");
1150
1151 return json_object;
1152}

References ast_json_pack().

Referenced by conf_run(), and send_talking_event().

◆ tweak_listen_volume()

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

Definition at line 1328 of file app_meetme.c.

1329{
1330 tweak_volume(&user->listen, action);
1331 /* attempt to make the adjustment in the channel driver;
1332 if successful, don't adjust in the frame reading routine
1333 */
1334 if (!set_listen_volume(user, user->listen.desired))
1335 user->listen.actual = 0;
1336 else
1337 user->listen.actual = user->listen.desired;
1338}
static void tweak_volume(struct volume *vol, enum volume_action action)
Definition: app_meetme.c:1281
static int set_listen_volume(struct ast_conf_user *user, int volume)
Definition: app_meetme.c:1269

References set_listen_volume(), and tweak_volume().

Referenced by admin_exec(), meetme_menu_admin(), meetme_menu_normal(), user_listen_voldown_cb(), and user_listen_volup_cb().

◆ tweak_talk_volume()

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

Definition at line 1316 of file app_meetme.c.

1317{
1318 tweak_volume(&user->talk, action);
1319 /* attempt to make the adjustment in the channel driver;
1320 if successful, don't adjust in the frame reading routine
1321 */
1322 if (!set_talk_volume(user, user->talk.desired))
1323 user->talk.actual = 0;
1324 else
1325 user->talk.actual = user->talk.desired;
1326}

References set_talk_volume(), and tweak_volume().

Referenced by admin_exec(), meetme_menu_admin(), meetme_menu_normal(), user_talk_voldown_cb(), and user_talk_volup_cb().

◆ tweak_volume()

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

Definition at line 1281 of file app_meetme.c.

1282{
1283 switch (action) {
1284 case VOL_UP:
1285 switch (vol->desired) {
1286 case 5:
1287 break;
1288 case 0:
1289 vol->desired = 2;
1290 break;
1291 case -2:
1292 vol->desired = 0;
1293 break;
1294 default:
1295 vol->desired++;
1296 break;
1297 }
1298 break;
1299 case VOL_DOWN:
1300 switch (vol->desired) {
1301 case -5:
1302 break;
1303 case 2:
1304 vol->desired = 0;
1305 break;
1306 case 0:
1307 vol->desired = -2;
1308 break;
1309 default:
1310 vol->desired--;
1311 break;
1312 }
1313 }
1314}
int desired
Definition: app_meetme.c:899

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 5493 of file app_meetme.c.

5494{
5495 int res = 0;
5496
5498 res = ast_manager_unregister("MeetmeMute");
5499 res |= ast_manager_unregister("MeetmeUnmute");
5500 res |= ast_manager_unregister("MeetmeList");
5501 res |= ast_manager_unregister("MeetmeListRooms");
5506
5507 ast_devstate_prov_del("Meetme");
5508
5510 ast_unload_realtime("meetme");
5511
5513
5514 return res;
5515}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_devstate_prov_del(const char *label)
Remove device state provider.
Definition: devicestate.c:418
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8057
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.

References app, app2, app3, app4, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_devstate_prov_del(), ast_manager_unregister(), ast_unload_realtime(), ast_unregister_application(), cli_meetme, meetme_info_acf, and meetme_stasis_cleanup().

◆ user_chan_cb()

static int user_chan_cb ( void *  obj,
void *  args,
int  flags 
)
static

Definition at line 4762 of file app_meetme.c.

4763{
4764 struct ast_conf_user *user = obj;
4765 const char *channel = args;
4766
4767 if (!strcmp(ast_channel_name(user->chan), channel)) {
4768 return (CMP_MATCH | CMP_STOP);
4769 }
4770
4771 return 0;
4772}
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028

References args, ast_channel_name(), CMP_MATCH, and CMP_STOP.

Referenced by channel_admin_exec().

◆ user_listen_voldown_cb()

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

Definition at line 4734 of file app_meetme.c.

4735{
4736 struct ast_conf_user *user = obj;
4738 return 0;
4739}

References tweak_listen_volume(), and VOL_DOWN.

Referenced by admin_exec().

◆ user_listen_volup_cb()

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

Definition at line 4727 of file app_meetme.c.

4728{
4729 struct ast_conf_user *user = obj;
4731 return 0;
4732}

References tweak_listen_volume(), and VOL_UP.

Referenced by admin_exec().

◆ user_max_cmp()

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

Definition at line 1401 of file app_meetme.c.

1402{
1403 struct ast_conf_user *user = obj;
1404 int *max_no = arg;
1405
1406 if (user->user_no > *max_no) {
1407 *max_no = user->user_no;
1408 }
1409
1410 return 0;
1411}

Referenced by admin_exec(), conf_run(), and meetme_menu_admin().

◆ user_no_cmp()

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

Definition at line 1389 of file app_meetme.c.

1390{
1391 struct ast_conf_user *user = obj;
1392 int *user_no = arg;
1393
1394 if (user->user_no == *user_no) {
1395 return (CMP_MATCH | CMP_STOP);
1396 }
1397
1398 return 0;
1399}

References CMP_MATCH, CMP_STOP, and ast_conf_user::user_no.

Referenced by build_conf().

◆ user_reset_vol_cb()

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

Definition at line 4755 of file app_meetme.c.

4756{
4757 struct ast_conf_user *user = obj;
4759 return 0;
4760}

References reset_volumes().

Referenced by admin_exec().

◆ user_set_hangup_cb()

static int user_set_hangup_cb ( void *  obj,
void *  check_admin_arg,
int  flags 
)
static

Definition at line 2266 of file app_meetme.c.

2267{
2268 struct ast_conf_user *user = obj;
2269 /* actual pointer contents of check_admin_arg is irrelevant */
2270
2271 if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
2272 user->adminflags |= ADMINFLAG_HANGUP;
2273 }
2274 return 0;
2275}

References ADMINFLAG_HANGUP, ast_test_flag64, and CONFFLAG_ADMIN.

Referenced by conf_run().

◆ user_set_kickme_cb()

static int user_set_kickme_cb ( void *  obj,
void *  check_admin_arg,
int  flags 
)
static

Definition at line 2277 of file app_meetme.c.

2278{
2279 struct ast_conf_user *user = obj;
2280 /* actual pointer contents of check_admin_arg is irrelevant */
2281
2282 if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
2283 user->adminflags |= ADMINFLAG_KICKME;
2284 }
2285 return 0;
2286}

References ADMINFLAG_KICKME, ast_test_flag64, and CONFFLAG_ADMIN.

Referenced by admin_exec(), and meetme_menu_admin_extended().

◆ user_set_muted_cb()

static int user_set_muted_cb ( void *  obj,
void *  check_admin_arg,
int  flags 
)
static

Definition at line 2299 of file app_meetme.c.

2300{
2301 struct ast_conf_user *user = obj;
2302 /* actual pointer contents of check_admin_arg is irrelevant */
2303
2304 if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
2305 user->adminflags |= ADMINFLAG_MUTED;
2306 }
2307 return 0;
2308}

References ADMINFLAG_MUTED, ast_test_flag64, and CONFFLAG_ADMIN.

Referenced by admin_exec(), and meetme_menu_admin_extended().

◆ user_set_unmuted_cb()

static int user_set_unmuted_cb ( void *  obj,
void *  check_admin_arg,
int  flags 
)
static

Definition at line 2288 of file app_meetme.c.

2289{
2290 struct ast_conf_user *user = obj;
2291 /* actual pointer contents of check_admin_arg is irrelevant */
2292
2293 if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
2295 }
2296 return 0;
2297}

References ADMINFLAG_MUTED, ADMINFLAG_SELFMUTED, ADMINFLAG_T_REQUEST, ast_test_flag64, and CONFFLAG_ADMIN.

Referenced by admin_exec(), and meetme_menu_admin_extended().

◆ user_talk_voldown_cb()

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

Definition at line 4748 of file app_meetme.c.

4749{
4750 struct ast_conf_user *user = obj;
4752 return 0;
4753}

References tweak_talk_volume(), and VOL_DOWN.

Referenced by admin_exec().

◆ user_talk_volup_cb()

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

Definition at line 4741 of file app_meetme.c.

4742{
4743 struct ast_conf_user *user = obj;
4745 return 0;
4746}

References tweak_talk_volume(), and VOL_UP.

Referenced by admin_exec().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "MeetMe conference bridge" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_DEPRECATED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, .optional_modules = "func_speex", }
static

Definition at line 5566 of file app_meetme.c.

◆ app

const char* const app = "MeetMe"
static

Definition at line 812 of file app_meetme.c.

Referenced by load_module(), and unload_module().

◆ app2

const char* const app2 = "MeetMeCount"
static

Definition at line 813 of file app_meetme.c.

Referenced by load_module(), and unload_module().

◆ app3

const char* const app3 = "MeetMeAdmin"
static

Definition at line 814 of file app_meetme.c.

Referenced by load_module(), and unload_module().

◆ app4

const char* const app4 = "MeetMeChannelAdmin"
static

Definition at line 815 of file app_meetme.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 5566 of file app_meetme.c.

◆ audio_buffers

int audio_buffers
static

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

Definition at line 928 of file app_meetme.c.

Referenced by conf_run(), load_config_meetme(), and meetme_set_defaults().

◆ cli_meetme

struct ast_cli_entry cli_meetme[]
static

Definition at line 1937 of file app_meetme.c.

Referenced by load_module(), and unload_module().

◆ conf_map

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

Definition at line 896 of file app_meetme.c.

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

◆ confs

struct confs confs = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
static

◆ earlyalert

int earlyalert
static

Definition at line 820 of file app_meetme.c.

Referenced by find_conf_realtime(), load_config_meetme(), and meetme_set_defaults().

◆ endalert

int endalert
static

Definition at line 821 of file app_meetme.c.

Referenced by find_conf_realtime(), load_config_meetme(), and meetme_set_defaults().

◆ extendby

int extendby
static

Definition at line 822 of file app_meetme.c.

Referenced by load_config_meetme(), meetme_set_defaults(), and rt_extend_conf().

◆ fuzzystart

int fuzzystart
static

Definition at line 819 of file app_meetme.c.

Referenced by find_conf_realtime(), load_config_meetme(), and meetme_set_defaults().

◆ gain_map

const char 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 937 of file app_meetme.c.

Referenced by set_listen_volume(), and set_talk_volume().

◆ meetme_event_message_router

struct stasis_message_router* meetme_event_message_router
static

Definition at line 952 of file app_meetme.c.

Referenced by meetme_stasis_cleanup(), and meetme_stasis_init().

◆ meetme_info_acf

struct ast_custom_function meetme_info_acf
static
Initial value:
= {
.name = "MEETME_INFO",
.read = acf_meetme_info,
}
static int acf_meetme_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: app_meetme.c:5432

Definition at line 5482 of file app_meetme.c.

Referenced by load_module(), and unload_module().

◆ meetme_opts

const struct ast_app_option meetme_opts[128] = { [ 'A' ] = { .flag = CONFFLAG_MARKEDUSER }, [ 'a' ] = { .flag = CONFFLAG_ADMIN }, [ 'b' ] = { .flag = CONFFLAG_AGI }, [ 'c' ] = { .flag = CONFFLAG_ANNOUNCEUSERCOUNT }, [ 'C' ] = { .flag = CONFFLAG_KICK_CONTINUE }, [ 'D' ] = { .flag = CONFFLAG_DYNAMICPIN }, [ 'd' ] = { .flag = CONFFLAG_DYNAMIC }, [ 'E' ] = { .flag = CONFFLAG_EMPTYNOPIN }, [ 'e' ] = { .flag = CONFFLAG_EMPTY }, [ 'F' ] = { .flag = CONFFLAG_PASS_DTMF }, [ 'G' ] = { .flag = (1ULL << 32) , .arg_index = OPT_ARG_INTROMSG + 1 }, [ 'v' ] = { .flag = (1ULL << 33) , .arg_index = OPT_ARG_INTROUSER_VMREC + 1 }, [ 'i' ] = { .flag = CONFFLAG_INTROUSER }, [ 'I' ] = { .flag = CONFFLAG_INTROUSERNOREVIEW }, [ 'k' ] = { .flag = (1ULL << 34) }, [ 'M' ] = { .flag = CONFFLAG_MOH , .arg_index = OPT_ARG_MOH_CLASS + 1 }, [ 'm' ] = { .flag = CONFFLAG_STARTMUTED }, [ 'n' ] = { .flag = (1ULL << 35) }, [ 'o' ] = { .flag = CONFFLAG_OPTIMIZETALKER }, [ 'P' ] = { .flag = CONFFLAG_ALWAYSPROMPT }, [ 'p' ] = { .flag = CONFFLAG_KEYEXIT , .arg_index = OPT_ARG_EXITKEYS + 1 }, [ 'q' ] = { .flag = CONFFLAG_QUIET }, [ 'r' ] = { .flag = CONFFLAG_RECORDCONF }, [ 's' ] = { .flag = CONFFLAG_STARMENU }, [ 'T' ] = { .flag = CONFFLAG_MONITORTALKER }, [ 'l' ] = { .flag = CONFFLAG_MONITOR }, [ 't' ] = { .flag = CONFFLAG_TALKER }, [ 'w' ] = { .flag = CONFFLAG_WAITMARKED , .arg_index = OPT_ARG_WAITMARKED + 1 }, [ 'X' ] = { .flag = CONFFLAG_EXIT_CONTEXT }, [ 'x' ] = { .flag = CONFFLAG_MARKEDEXIT }, [ '1' ] = { .flag = CONFFLAG_NOONLYPERSON }, [ 'S' ] = { .flag = CONFFLAG_DURATION_STOP , .arg_index = OPT_ARG_DURATION_STOP + 1 }, [ 'L' ] = { .flag = CONFFLAG_DURATION_LIMIT , .arg_index = OPT_ARG_DURATION_LIMIT + 1 }, }
static

Definition at line 810 of file app_meetme.c.

Referenced by conf_exec(), and find_conf_realtime().

◆ rt_log_members

int rt_log_members
static

Log participant count to the RealTime backend

Definition at line 825 of file app_meetme.c.

Referenced by conf_run(), load_config_meetme(), and meetme_set_defaults().

◆ rt_schedule

int rt_schedule
static