Sun Aug 6 15:03:49 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

app_meetme.c File Reference

Meet me conference bridge. More...

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <zaptel.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/options.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "enter.h"
#include "leave.h"

Include dependency graph for app_meetme.c:

Go to the source code of this file.

Defines

#define ADMINFLAG_KICKME   (1 << 2)
#define ADMINFLAG_MUTED   (1 << 1)
#define CONF_COMMANDS   6
#define CONF_SIZE   320
#define CONFFLAG_ADMIN   (1 << 1)
#define CONFFLAG_AGI   (1 << 8)
#define CONFFLAG_ALWAYSPROMPT   (1 << 21)
#define CONFFLAG_ANNOUNCEUSERCOUNT   (1 << 7)
#define CONFFLAG_DYNAMIC   (1 << 17)
#define CONFFLAG_DYNAMICPIN   (1 << 18)
#define CONFFLAG_EMPTY   (1 << 19)
#define CONFFLAG_EMPTYNOPIN   (1 << 20)
#define CONFFLAG_EXIT_CONTEXT   (1 << 12)
#define CONFFLAG_INTROUSER   (1 << 14)
#define CONFFLAG_MARKEDEXIT   (1 << 10)
#define CONFFLAG_MARKEDUSER   (1 << 13)
#define CONFFLAG_MOH   (1 << 9)
#define CONFFLAG_MONITOR   (1 << 2)
#define CONFFLAG_MONITORTALKER   (1 << 16)
#define CONFFLAG_POUNDEXIT   (1 << 3)
#define CONFFLAG_QUIET   (1 << 6)
#define CONFFLAG_RECORDCONF   (1<< 15)
#define CONFFLAG_STARMENU   (1 << 4)
#define CONFFLAG_TALKER   (1 << 5)
#define CONFFLAG_WAITMARKED   (1 << 11)
#define CONFIG_FILE_NAME   "meetme.conf"
#define DEFAULT_AUDIO_BUFFERS   32
#define ENTER   0
#define LEAVE   1
#define MEETME_DELAYDETECTENDTALK   1000
#define MEETME_DELAYDETECTTALK   300
#define MEETME_RECORD_ACTIVE   1
#define MEETME_RECORD_OFF   0
#define MEETME_RECORD_TERMINATE   2

Enumerations

enum  volume_action { VOL_UP, VOL_DOWN }

Functions

static int admin_exec (struct ast_channel *chan, void *data)
 AST_APP_OPTIONS (meetme_opts,{AST_APP_OPTION('a', CONFFLAG_ADMIN), AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT), AST_APP_OPTION('T', CONFFLAG_MONITORTALKER), AST_APP_OPTION('i', CONFFLAG_INTROUSER), AST_APP_OPTION('m', CONFFLAG_MONITOR), AST_APP_OPTION('p', CONFFLAG_POUNDEXIT), AST_APP_OPTION('s', CONFFLAG_STARMENU), AST_APP_OPTION('t', CONFFLAG_TALKER), AST_APP_OPTION('q', CONFFLAG_QUIET), AST_APP_OPTION('M', CONFFLAG_MOH), AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT), AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT), AST_APP_OPTION('A', CONFFLAG_MARKEDUSER), AST_APP_OPTION('b', CONFFLAG_AGI), AST_APP_OPTION('w', CONFFLAG_WAITMARKED), AST_APP_OPTION('r', CONFFLAG_RECORDCONF), AST_APP_OPTION('d', CONFFLAG_DYNAMIC), AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN), AST_APP_OPTION('e', CONFFLAG_EMPTY), AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN), AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT),})
 AST_MUTEX_DEFINE_STATIC (conflock)
static struct ast_conferencebuild_conf (char *confno, char *pin, char *pinadmin, int make, int dynamic)
static int careful_write (int fd, unsigned char *data, int len, int block)
static char * complete_confcmd (char *line, char *word, int pos, int state)
static int conf_cmd (int fd, int argc, char **argv)
static int conf_exec (struct ast_channel *chan, void *data)
static void conf_flush (int fd, struct ast_channel *chan)
static int conf_free (struct ast_conference *conf)
static void conf_play (struct ast_channel *chan, struct ast_conference *conf, int sound)
static int conf_run (struct ast_channel *chan, struct ast_conference *conf, int confflags)
static int confs_show (int fd, int argc, char **argv)
static int count_exec (struct ast_channel *chan, void *data)
char * description (void)
 Provides a description of the module.
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, struct ast_flags *confflags)
static struct ast_conf_userfind_user (struct ast_conference *conf, char *callerident)
static char * istalking (int x)
char * key ()
 Returns the ASTERISK_GPL_KEY.
static void load_config (void)
int load_module (void)
 Initialize the module.
static void * recordthread (void *args)
int reload (void)
 Reload stuff.
static void reset_volumes (struct ast_conf_user *user)
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 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)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
int usecount (void)
 Provides a usecount.

Variables

static const char * app = "MeetMe"
static const char * app2 = "MeetMeCount"
static const char * app3 = "MeetMeAdmin"
static int audio_buffers
static struct ast_cli_entry cli_conf
static struct ast_cli_entry cli_show_confs
static char conf_usage []
static struct ast_conferenceconfs
static const char * descrip
static const char * descrip2
static const char * descrip3
static signed char gain_map []
 LOCAL_USER_DECL
static char show_confs_usage []
 STANDARD_LOCAL_USER
static const char * synopsis = "MeetMe conference bridge"
static const char * synopsis2 = "MeetMe participant count"
static const char * synopsis3 = "MeetMe conference Administration"
static const char * tdesc = "MeetMe conference bridge"


Detailed Description

Meet me conference bridge.

Definition in file app_meetme.c.


Define Documentation

#define ADMINFLAG_KICKME   (1 << 2)
 

Definition at line 181 of file app_meetme.c.

Referenced by admin_exec(), and conf_run().

#define ADMINFLAG_MUTED   (1 << 1)
 

Definition at line 180 of file app_meetme.c.

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

#define CONF_COMMANDS   6
 

Referenced by complete_confcmd().

#define CONF_SIZE   320
 

Definition at line 206 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_ADMIN   (1 << 1)
 

Definition at line 208 of file app_meetme.c.

Referenced by admin_exec(), conf_cmd(), conf_exec(), and conf_run().

#define CONFFLAG_AGI   (1 << 8)
 

Definition at line 215 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_ALWAYSPROMPT   (1 << 21)
 

Definition at line 228 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_ANNOUNCEUSERCOUNT   (1 << 7)
 

Definition at line 214 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_DYNAMIC   (1 << 17)
 

Definition at line 224 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_DYNAMICPIN   (1 << 18)
 

Definition at line 225 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_EMPTY   (1 << 19)
 

Definition at line 226 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_EMPTYNOPIN   (1 << 20)
 

Definition at line 227 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_EXIT_CONTEXT   (1 << 12)
 

Definition at line 219 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_INTROUSER   (1 << 14)
 

Definition at line 221 of file app_meetme.c.

Referenced by conf_run(), and find_conf().

#define CONFFLAG_MARKEDEXIT   (1 << 10)
 

Definition at line 217 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_MARKEDUSER   (1 << 13)
 

Definition at line 220 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_MOH   (1 << 9)
 

Definition at line 216 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_MONITOR   (1 << 2)
 

Definition at line 209 of file app_meetme.c.

Referenced by conf_cmd(), and conf_run().

#define CONFFLAG_MONITORTALKER   (1 << 16)
 

Definition at line 223 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_POUNDEXIT   (1 << 3)
 

Definition at line 210 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_QUIET   (1 << 6)
 

Definition at line 213 of file app_meetme.c.

Referenced by conf_run(), and find_conf().

#define CONFFLAG_RECORDCONF   (1<< 15)
 

Definition at line 222 of file app_meetme.c.

Referenced by conf_run(), and find_conf().

#define CONFFLAG_STARMENU   (1 << 4)
 

Definition at line 211 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_TALKER   (1 << 5)
 

Definition at line 212 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_WAITMARKED   (1 << 11)
 

Definition at line 218 of file app_meetme.c.

Referenced by conf_run().

#define CONFIG_FILE_NAME   "meetme.conf"
 

Definition at line 125 of file app_meetme.c.

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

#define DEFAULT_AUDIO_BUFFERS   32
 

Definition at line 178 of file app_meetme.c.

Referenced by load_config().

#define ENTER   0
 

Definition at line 199 of file app_meetme.c.

Referenced by conf_play(), and conf_run().

#define LEAVE   1
 

Definition at line 200 of file app_meetme.c.

Referenced by conf_play(), and conf_run().

#define MEETME_DELAYDETECTENDTALK   1000
 

Definition at line 183 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300
 

Definition at line 182 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_RECORD_ACTIVE   1
 

Definition at line 203 of file app_meetme.c.

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

#define MEETME_RECORD_OFF   0
 

Definition at line 202 of file app_meetme.c.

Referenced by conf_free(), and recordthread().

#define MEETME_RECORD_TERMINATE   2
 

Definition at line 204 of file app_meetme.c.

Referenced by conf_free(), and recordthread().


Enumeration Type Documentation

enum volume_action
 

Enumeration values:
VOL_UP 
VOL_DOWN 

Definition at line 185 of file app_meetme.c.

00185                    {
00186    VOL_UP,
00187    VOL_DOWN,
00188 };


Function Documentation

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

Definition at line 2040 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ast_conf_user::adminflags, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), CONFFLAG_ADMIN, ast_conference::confno, confs, find_user(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_NOTICE, LOG_WARNING, ast_conference::next, ast_conf_user::nextuser, strsep(), user, and ast_conf_user::userflags.

Referenced by conf_cmd(), and load_module().

02040                                                             {
02041    char *params, *command = NULL, *caller = NULL, *conf = NULL;
02042    struct ast_conference *cnf;
02043    struct ast_conf_user *user = NULL;
02044    struct localuser *u;
02045    
02046    LOCAL_USER_ADD(u);
02047 
02048    ast_mutex_lock(&conflock);
02049    /* The param has the conference number the user and the command to execute */
02050    if (!ast_strlen_zero(data)) {    
02051       params = ast_strdupa((char *) data);
02052       conf = strsep(&params, "|");
02053       command = strsep(&params, "|");
02054       caller = strsep(&params, "|");
02055       
02056       if (!command) {
02057          ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
02058          ast_mutex_unlock(&conflock);
02059          LOCAL_USER_REMOVE(u);
02060          return -1;
02061       }
02062       for (cnf = confs; cnf; cnf = cnf->next) {
02063          if (!strcmp(cnf->confno, conf))
02064             break;
02065       }
02066       
02067       if (caller)
02068          user = find_user(cnf, caller);
02069       
02070       if (cnf) {
02071          switch((int) (*command)) {
02072          case 76: /* L: Lock */ 
02073             cnf->locked = 1;
02074             break;
02075          case 108: /* l: Unlock */ 
02076             cnf->locked = 0;
02077             break;
02078          case 75: /* K: kick all users*/
02079             user = cnf->firstuser;
02080             while(user) {
02081                user->adminflags |= ADMINFLAG_KICKME;
02082                if (user->nextuser) {
02083                   user = user->nextuser;
02084                } else {
02085                   break;
02086                }
02087             }
02088             break;
02089          case 101: /* e: Eject last user*/
02090             user = cnf->lastuser;
02091             if (!(user->userflags & CONFFLAG_ADMIN)) {
02092                user->adminflags |= ADMINFLAG_KICKME;
02093                break;
02094             } else
02095                ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
02096             break;
02097          case 77: /* M: Mute */ 
02098             if (user) {
02099                user->adminflags |= ADMINFLAG_MUTED;
02100             } else {
02101                ast_log(LOG_NOTICE, "Specified User not found!\n");
02102             }
02103             break;
02104          case 78: /* N: Mute all users */
02105             user = cnf->firstuser;
02106             while(user) {
02107                if (user && !(user->userflags & CONFFLAG_ADMIN))
02108                   user->adminflags |= ADMINFLAG_MUTED;
02109                if (user->nextuser) {
02110                   user = user->nextuser;
02111                } else {
02112                   break;
02113                }
02114             }
02115             break;               
02116          case 109: /* m: Unmute */ 
02117             if (user && (user->adminflags & ADMINFLAG_MUTED)) {
02118                user->adminflags ^= ADMINFLAG_MUTED;
02119             } else {
02120                ast_log(LOG_NOTICE, "Specified User not found or he muted himself!\n");
02121             }
02122             break;
02123          case  110: /* n: Unmute all users */
02124             user = cnf->firstuser;
02125             while(user) {
02126                if (user && (user-> adminflags & ADMINFLAG_MUTED)) {
02127                   user->adminflags ^= ADMINFLAG_MUTED;
02128                }
02129                if (user->nextuser) {
02130                   user = user->nextuser;
02131                } else {
02132                   break;
02133                }
02134             }
02135             break;
02136          case 107: /* k: Kick user */ 
02137             if (user) {
02138                user->adminflags |= ADMINFLAG_KICKME;
02139             } else {
02140                ast_log(LOG_NOTICE, "Specified User not found!\n");
02141             }
02142             break;
02143          }
02144       } else {
02145          ast_log(LOG_NOTICE, "Conference Number not found\n");
02146       }
02147    }
02148    ast_mutex_unlock(&conflock);
02149 
02150    LOCAL_USER_REMOVE(u);
02151    
02152    return 0;
02153 }

AST_APP_OPTIONS meetme_opts   ) 
 

AST_MUTEX_DEFINE_STATIC conflock   ) 
 

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

Definition at line 436 of file app_meetme.c.

References AST_FORMAT_ULAW, ast_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_request(), ast_verbose(), calloc, ast_conference::confno, confs, free, LOG_WARNING, ast_conference::next, option_verbose, and VERBOSE_PREFIX_3.

Referenced by find_conf().

00437 {
00438    struct ast_conference *cnf;
00439    struct zt_confinfo ztc;
00440 
00441    ast_mutex_lock(&conflock);
00442 
00443    for (cnf = confs; cnf; cnf = cnf->next) {
00444       if (!strcmp(confno, cnf->confno)) 
00445          break;
00446    }
00447 
00448    if (!cnf && (make || dynamic)) {
00449       /* Make a new one */
00450       cnf = calloc(1, sizeof(*cnf));
00451       if (cnf) {
00452          ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00453          ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00454          ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00455          cnf->markedusers = 0;
00456          cnf->chan = ast_request("zap", AST_FORMAT_ULAW, "pseudo", NULL);
00457          if (cnf->chan) {
00458             cnf->fd = cnf->chan->fds[0];  /* for use by conf_play() */
00459          } else {
00460             ast_log(LOG_WARNING, "Unable to open pseudo channel - trying device\n");
00461             cnf->fd = open("/dev/zap/pseudo", O_RDWR);
00462             if (cnf->fd < 0) {
00463                ast_log(LOG_WARNING, "Unable to open pseudo device\n");
00464                free(cnf);
00465                cnf = NULL;
00466                goto cnfout;
00467             }
00468          }
00469          memset(&ztc, 0, sizeof(ztc));
00470          /* Setup a new zap conference */
00471          ztc.chan = 0;
00472          ztc.confno = -1;
00473          ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
00474          if (ioctl(cnf->fd, ZT_SETCONF, &ztc)) {
00475             ast_log(LOG_WARNING, "Error setting conference\n");
00476             if (cnf->chan)
00477                ast_hangup(cnf->chan);
00478             else
00479                close(cnf->fd);
00480             free(cnf);
00481             cnf = NULL;
00482             goto cnfout;
00483          }
00484          /* Fill the conference struct */
00485          cnf->start = time(NULL);
00486          cnf->zapconf = ztc.confno;
00487          cnf->isdynamic = dynamic;
00488          cnf->firstuser = NULL;
00489          cnf->lastuser = NULL;
00490          cnf->locked = 0;
00491          if (option_verbose > 2)
00492             ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
00493          cnf->next = confs;
00494          confs = cnf;
00495       } else   
00496          ast_log(LOG_WARNING, "Out of memory\n");
00497    }
00498  cnfout:
00499    ast_mutex_unlock(&conflock);
00500    return cnf;
00501 }

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

Definition at line 265 of file app_meetme.c.

References ast_log(), and LOG_WARNING.

Referenced by conf_play(), and conf_run().

00266 {
00267    int res;
00268    int x;
00269 
00270    while (len) {
00271       if (block) {
00272          x = ZT_IOMUX_WRITE | ZT_IOMUX_SIGEVENT;
00273          res = ioctl(fd, ZT_IOMUX, &x);
00274       } else
00275          res = 0;
00276       if (res >= 0)
00277          res = write(fd, data, len);
00278       if (res < 1) {
00279          if (errno != EAGAIN) {
00280             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00281             return -1;
00282          } else
00283             return 0;
00284       }
00285       len -= res;
00286       data += res;
00287    }
00288 
00289    return 0;
00290 }

static char* complete_confcmd char *  line,
char *  word,
int  pos,
int  state
[static]
 

Definition at line 643 of file app_meetme.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, CONF_COMMANDS, ast_conference::confno, confs, ast_conference::firstuser, ast_conference::next, ast_conf_user::nextuser, strdup, strsep(), and ast_conf_user::user_no.

00643                                                                           {
00644 #define CONF_COMMANDS 6
00645    int which = 0, x = 0;
00646    struct ast_conference *cnf = NULL;
00647    struct ast_conf_user *usr = NULL;
00648    char *confno = NULL;
00649    char usrno[50] = "";
00650    char cmds[CONF_COMMANDS][20] = {"lock", "unlock", "mute", "unmute", "kick", "list"};
00651    char *myline;
00652    
00653    if (pos == 1) {
00654       /* Command */
00655       for (x = 0;x < CONF_COMMANDS; x++) {
00656          if (!strncasecmp(cmds[x], word, strlen(word))) {
00657             if (++which > state) {
00658                return strdup(cmds[x]);
00659             }
00660          }
00661       }
00662    } else if (pos == 2) {
00663       /* Conference Number */
00664       ast_mutex_lock(&conflock);
00665       cnf = confs;
00666       while(cnf) {
00667          if (!strncasecmp(word, cnf->confno, strlen(word))) {
00668             if (++which > state)
00669                break;
00670          }
00671          cnf = cnf->next;
00672       }
00673       ast_mutex_unlock(&conflock);
00674       return cnf ? strdup(cnf->confno) : NULL;
00675    } else if (pos == 3) {
00676       /* User Number || Conf Command option*/
00677       if (strstr(line, "mute") || strstr(line, "kick")) {
00678          if ((state == 0) && (strstr(line, "kick") || strstr(line,"mute")) && !(strncasecmp(word, "all", strlen(word)))) {
00679             return strdup("all");
00680          }
00681          which++;
00682          ast_mutex_lock(&conflock);
00683 
00684          /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
00685          myline = ast_strdupa(line);
00686          if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
00687             while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
00688                ;
00689          }
00690          
00691          for (cnf = confs; cnf; cnf = cnf->next) {
00692             if (!strcmp(confno, cnf->confno))
00693                 break;
00694          }
00695 
00696          if (cnf) {
00697             /* Search for the user */
00698             for (usr = cnf->firstuser; usr; usr = usr->nextuser) {
00699                snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
00700                if (!strncasecmp(word, usrno, strlen(word))) {
00701                   if (++which > state)
00702                      break;
00703                }
00704             }
00705          }
00706          ast_mutex_unlock(&conflock);
00707          return usr ? strdup(usrno) : NULL;
00708       }
00709    }
00710 
00711    return NULL;
00712 }

static int conf_cmd int  fd,
int  argc,
char **  argv
[static]
 

Definition at line 517 of file app_meetme.c.

References admin_exec(), ADMINFLAG_MUTED, ast_conf_user::adminflags, ast_cli(), ast_log(), ast_conf_user::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, confs, ast_conference::firstuser, ast_conference::isdynamic, istalking(), LOG_DEBUG, ast_conference::markedusers, ast_channel::name, ast_conference::next, ast_conf_user::nextuser, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_conference::start, ast_conf_user::talking, total, user, ast_conf_user::user_no, ast_conf_user::userflags, and ast_conference::users.

00517                                                    {
00518    /* Process the command */
00519    struct ast_conference *cnf;
00520    struct ast_conf_user *user;
00521    int hr, min, sec;
00522    int i = 0, total = 0;
00523    time_t now;
00524    char *header_format = "%-14s %-14s %-10s %-8s  %-8s\n";
00525    char *data_format = "%-12.12s   %4.4d        %4.4s       %02d:%02d:%02d  %-8s\n";
00526    char cmdline[1024] = "";
00527 
00528    if (argc > 8)
00529       ast_cli(fd, "Invalid Arguments.\n");
00530    /* Check for length so no buffer will overflow... */
00531    for (i = 0; i < argc; i++) {
00532       if (strlen(argv[i]) > 100)
00533          ast_cli(fd, "Invalid Arguments.\n");
00534    }
00535    if (argc == 1) {
00536       /* 'MeetMe': List all the conferences */  
00537       now = time(NULL);
00538       cnf = confs;
00539       if (!cnf) {
00540          ast_cli(fd, "No active MeetMe conferences.\n");
00541          return RESULT_SUCCESS;
00542       }
00543       ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
00544       while(cnf) {
00545          if (cnf->markedusers == 0)
00546             strcpy(cmdline, "N/A ");
00547          else 
00548             snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers);
00549          hr = (now - cnf->start) / 3600;
00550          min = ((now - cnf->start) % 3600) / 60;
00551          sec = (now - cnf->start) % 60;
00552 
00553          ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static");
00554 
00555          total += cnf->users;    
00556          cnf = cnf->next;
00557       }
00558       ast_cli(fd, "* Total number of MeetMe users: %d\n", total);
00559       return RESULT_SUCCESS;
00560    }
00561    if (argc < 3)
00562       return RESULT_SHOWUSAGE;
00563    ast_copy_string(cmdline, argv[2], sizeof(cmdline));   /* Argv 2: conference number */
00564    if (strstr(argv[1], "lock")) {   
00565       if (strcmp(argv[1], "lock") == 0) {
00566          /* Lock */
00567          strncat(cmdline, "|L", sizeof(cmdline) - strlen(cmdline) - 1);
00568       } else {
00569          /* Unlock */
00570          strncat(cmdline, "|l", sizeof(cmdline) - strlen(cmdline) - 1);
00571       }
00572    } else if (strstr(argv[1], "mute")) { 
00573       if (argc < 4)
00574          return RESULT_SHOWUSAGE;
00575       if (strcmp(argv[1], "mute") == 0) {
00576          /* Mute */
00577          if (strcmp(argv[3], "all") == 0) {
00578             strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1);
00579          } else {
00580             strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1);   
00581             strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00582          }
00583       } else {
00584          /* Unmute */
00585          if (strcmp(argv[3], "all") == 0) {
00586             strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1);
00587          } else {
00588             strncat(cmdline, "|m|", sizeof(cmdline) - strlen(cmdline) - 1);
00589             strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00590          }
00591       }
00592    } else if (strcmp(argv[1], "kick") == 0) {
00593       if (argc < 4)
00594          return RESULT_SHOWUSAGE;
00595       if (strcmp(argv[3], "all") == 0) {
00596          /* Kick all */
00597          strncat(cmdline, "|K", sizeof(cmdline) - strlen(cmdline) - 1);
00598       } else {
00599          /* Kick a single user */
00600          strncat(cmdline, "|k|", sizeof(cmdline) - strlen(cmdline) - 1);
00601          strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00602       }  
00603    } else if(strcmp(argv[1], "list") == 0) {
00604       /* List all the users in a conference */
00605       if (!confs) {
00606          ast_cli(fd, "No active conferences.\n");
00607          return RESULT_SUCCESS;  
00608       }
00609       cnf = confs;
00610       /* Find the right conference */
00611       while(cnf) {
00612          if (strcmp(cnf->confno, argv[2]) == 0)
00613             break;
00614          if (cnf->next) {
00615             cnf = cnf->next;  
00616          } else {
00617             ast_cli(fd, "No such conference: %s.\n",argv[2]);
00618             return RESULT_SUCCESS;
00619          }
00620       }
00621       /* Show all the users */
00622       for (user = cnf->firstuser; user; user = user->nextuser)
00623          ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s\n",
00624             user->user_no,
00625             user->chan->cid.cid_num ? user->chan->cid.cid_num : "<unknown>",
00626             user->chan->cid.cid_name ? user->chan->cid.cid_name : "<no name>",
00627             user->chan->name,
00628             user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
00629             user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
00630             user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : "",
00631             istalking(user->talking));
00632       ast_cli(fd,"%d users in that conference.\n",cnf->users);
00633 
00634       return RESULT_SUCCESS;
00635    } else 
00636       return RESULT_SHOWUSAGE;
00637    ast_log(LOG_DEBUG, "Cmdline: %s\n", cmdline);
00638    admin_exec(NULL, cmdline);
00639 
00640    return 0;
00641 }

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

Definition at line 1765 of file app_meetme.c.

References ast_channel::_state, ast_answer(), ast_app_getdata(), ast_app_parse_options(), ast_config_destroy(), ast_config_load(), AST_DIGIT_ANY, ast_log(), AST_MAX_EXTENSION, ast_mutex_lock(), ast_mutex_unlock(), ast_say_digits(), ast_set_flag, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_variable_browse(), ast_waitstream(), cfg, conf_free(), conf_run(), CONFFLAG_ADMIN, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFIG_FILE_NAME, ast_conference::confno, confs, find_conf(), ast_flags::flags, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, ast_conference::next, ast_conference::pin, ast_conference::pinadmin, strsep(), ast_conference::users, ast_variable::value, and var.

Referenced by load_module().

01766 {
01767    int res=-1;
01768    struct localuser *u;
01769    char confno[AST_MAX_EXTENSION] = "";
01770    int allowretry = 0;
01771    int retrycnt = 0;
01772    struct ast_conference *cnf;
01773    struct ast_flags confflags = {0};
01774    int dynamic = 0;
01775    int empty = 0, empty_no_pin = 0;
01776    int always_prompt = 0;
01777    char *notdata, *info, *inflags = NULL, *inpin = NULL, the_pin[AST_MAX_EXTENSION] = "";
01778 
01779    LOCAL_USER_ADD(u);
01780 
01781    if (ast_strlen_zero(data)) {
01782       allowretry = 1;
01783       notdata = "";
01784    } else {
01785       notdata = data;
01786    }
01787    
01788    if (chan->_state != AST_STATE_UP)
01789       ast_answer(chan);
01790 
01791    info = ast_strdupa(notdata);
01792 
01793    if (info) {
01794       char *tmp = strsep(&info, "|");
01795       ast_copy_string(confno, tmp, sizeof(confno));
01796       if (ast_strlen_zero(confno)) {
01797          allowretry = 1;
01798       }
01799    }
01800    if (info)
01801       inflags = strsep(&info, "|");
01802    if (info)
01803       inpin = strsep(&info, "|");
01804    if (inpin)
01805       ast_copy_string(the_pin, inpin, sizeof(the_pin));
01806 
01807    if (inflags) {
01808       ast_app_parse_options(meetme_opts, &confflags, NULL, inflags);
01809       dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
01810       if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !inpin)
01811          strcpy(the_pin, "q");
01812 
01813       empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
01814       empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
01815       always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
01816    }
01817 
01818    do {
01819       if (retrycnt > 3)
01820          allowretry = 0;
01821       if (empty) {
01822          int i, map[1024] = { 0, };
01823          struct ast_config *cfg;
01824          struct ast_variable *var;
01825          int confno_int;
01826 
01827          ast_mutex_lock(&conflock);
01828          for (cnf = confs; cnf; cnf = cnf->next) {
01829             if (sscanf(cnf->confno, "%d", &confno_int) == 1) {
01830                /* Disqualify in use conference */
01831                if (confno_int >= 0 && confno_int < 1024)
01832                   map[confno_int]++;
01833             }
01834          }
01835          ast_mutex_unlock(&conflock);
01836 
01837          /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
01838          if ((empty_no_pin) || (!dynamic)) {
01839             cfg = ast_config_load(CONFIG_FILE_NAME);
01840             if (cfg) {
01841                var = ast_variable_browse(cfg, "rooms");
01842                while (var) {
01843                   if (!strcasecmp(var->name, "conf")) {
01844                      char *stringp = ast_strdupa(var->value);
01845                      if (stringp) {
01846                         char *confno_tmp = strsep(&stringp, "|,");
01847                         int found = 0;
01848                         if (sscanf(confno_tmp, "%d", &confno_int) == 1) {
01849                            if ((confno_int >= 0) && (confno_int < 1024)) {
01850                               if (stringp && empty_no_pin) {
01851                                  map[confno_int]++;
01852                               }
01853                            }
01854                         }
01855                         if (!dynamic) {
01856                            /* For static:  run through the list and see if this conference is empty */
01857                            ast_mutex_lock(&conflock);
01858                            cnf = confs;
01859                            while (cnf) {
01860                               if (!strcmp(confno_tmp, cnf->confno)) {
01861                                  /* The conference exists, therefore it's not empty */
01862                                  found = 1;
01863                                  break;
01864                               }
01865                               cnf = cnf->next;
01866                            }
01867                            ast_mutex_unlock(&conflock);
01868                            if (!found) {
01869                               /* At this point, we have a confno_tmp (static conference) that is empty */
01870                               if ((empty_no_pin && ((!stringp) || (stringp && (stringp[0] == '\0')))) || (!empty_no_pin)) {
01871                                  /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
01872                                   * Case 2:  empty_no_pin and pin is blank (but not NULL)
01873                                   * Case 3:  not empty_no_pin
01874                                   */
01875                                  ast_copy_string(confno, confno_tmp, sizeof(confno));
01876                                  break;
01877                                  /* XXX the map is not complete (but we do have a confno) */
01878                               }
01879                            }
01880                         }
01881                      } else {
01882                         ast_log(LOG_ERROR, "Out of memory\n");
01883                      }
01884                   }
01885                   var = var->next;
01886                }
01887                ast_config_destroy(cfg);
01888             }
01889          }
01890 
01891          /* Select first conference number not in use */
01892          if (ast_strlen_zero(confno) && dynamic) {
01893             for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
01894                if (!map[i]) {
01895                   snprintf(confno, sizeof(confno), "%d", i);
01896                   break;
01897                }
01898             }
01899          }
01900 
01901          /* Not found? */
01902          if (ast_strlen_zero(confno)) {
01903             res = ast_streamfile(chan, "conf-noempty", chan->language);
01904             if (!res)
01905                ast_waitstream(chan, "");
01906          } else {
01907             if (sscanf(confno, "%d", &confno_int) == 1) {
01908                res = ast_streamfile(chan, "conf-enteringno", chan->language);
01909                if (!res) {
01910                   ast_waitstream(chan, "");
01911                   res = ast_say_digits(chan, confno_int, "", chan->language);
01912                }
01913             } else {
01914                ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
01915             }
01916          }
01917       }
01918 
01919       while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
01920          /* Prompt user for conference number */
01921          res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
01922          if (res < 0) {
01923             /* Don't try to validate when we catch an error */
01924             confno[0] = '\0';
01925             allowretry = 0;
01926             break;
01927          }
01928       }
01929       if (!ast_strlen_zero(confno)) {
01930          /* Check the validity of the conference */
01931          cnf = find_conf(chan, confno, 1, dynamic, the_pin, &confflags);
01932          if (!cnf) {
01933             res = ast_streamfile(chan, "conf-invalid", chan->language);
01934             if (!res)
01935                ast_waitstream(chan, "");
01936             res = -1;
01937             if (allowretry)
01938                confno[0] = '\0';
01939          } else {
01940             if ((!ast_strlen_zero(cnf->pin) &&
01941                  !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
01942                 (!ast_strlen_zero(cnf->pinadmin) &&
01943                  ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
01944                char pin[AST_MAX_EXTENSION]="";
01945                int j;
01946 
01947                /* Allow the pin to be retried up to 3 times */
01948                for (j = 0; j < 3; j++) {
01949                   if (*the_pin && (always_prompt == 0)) {
01950                      ast_copy_string(pin, the_pin, sizeof(pin));
01951                      res = 0;
01952                   } else {
01953                      /* Prompt user for pin if pin is required */
01954                      res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
01955                   }
01956                   if (res >= 0) {
01957                      if (!strcasecmp(pin, cnf->pin) ||
01958                          (!ast_strlen_zero(cnf->pinadmin) &&
01959                           !strcasecmp(pin, cnf->pinadmin))) {
01960                         /* Pin correct */
01961                         allowretry = 0;
01962                         if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
01963                            ast_set_flag(&confflags, CONFFLAG_ADMIN);
01964                         /* Run the conference */
01965                         res = conf_run(chan, cnf, confflags.flags);
01966                         break;
01967                      } else {
01968                         /* Pin invalid */
01969                         if (!ast_streamfile(chan, "conf-invalidpin", chan->language))
01970                            res = ast_waitstream(chan, AST_DIGIT_ANY);
01971                         else {
01972                            ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
01973                            break;
01974                         }
01975                         if (res < 0)
01976                            break;
01977                         pin[0] = res;
01978                         pin[1] = '\0';
01979                         res = -1;
01980                         if (allowretry)
01981                            confno[0] = '\0';
01982                      }
01983                   } else {
01984                      /* failed when getting the pin */
01985                      res = -1;
01986                      allowretry = 0;
01987                      /* see if we need to get rid of the conference */
01988                      ast_mutex_lock(&conflock);
01989                      if (!cnf->users) {
01990                         conf_free(cnf);   
01991                      }
01992                      ast_mutex_unlock(&conflock);
01993                      break;
01994                   }
01995 
01996                   /* Don't retry pin with a static pin */
01997                   if (*the_pin && (always_prompt==0)) {
01998                      break;
01999                   }
02000                }
02001             } else {
02002                /* No pin required */
02003                allowretry = 0;
02004 
02005                /* Run the conference */
02006                res = conf_run(chan, cnf, confflags.flags);
02007             }
02008          }
02009       }
02010    } while (allowretry);
02011    
02012    LOCAL_USER_REMOVE(u);
02013    
02014    return res;
02015 }

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

Definition at line 722 of file app_meetme.c.

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

Referenced by conf_run().

00723 {
00724    int x;
00725 
00726    /* read any frames that may be waiting on the channel
00727       and throw them away
00728    */
00729    if (chan) {
00730       struct ast_frame *f;
00731 
00732       /* when no frames are available, this will wait
00733          for 1 millisecond maximum
00734       */
00735       while (ast_waitfor(chan, 1)) {
00736          f = ast_read(chan);
00737          if (f)
00738             ast_frfree(f);
00739          else /* channel was hung up or something else happened */
00740             break;
00741       }
00742    }
00743 
00744    /* flush any data sitting in the pseudo channel */
00745    x = ZT_FLUSH_ALL;
00746    if (ioctl(fd, ZT_FLUSH, &x))
00747       ast_log(LOG_WARNING, "Error flushing channel\n");
00748 
00749 }

static int conf_free struct ast_conference conf  )  [static]
 

Definition at line 753 of file app_meetme.c.

References ast_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_conference::chan, confs, ast_conference::fd, free, LOG_WARNING, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, ast_conference::next, and ast_conference::recording.

Referenced by conf_exec(), and conf_run().

00754 {
00755    struct ast_conference *prev = NULL, *cur = confs;
00756 
00757    while (cur) {
00758       if (cur == conf) {
00759          if (prev)
00760             prev->next = conf->next;
00761          else
00762             confs = conf->next;
00763          break;
00764       }
00765       prev = cur;
00766       cur = cur->next;
00767    }
00768 
00769    if (!cur)
00770       ast_log(LOG_WARNING, "Conference not found\n");
00771 
00772    if (conf->recording == MEETME_RECORD_ACTIVE) {
00773       conf->recording = MEETME_RECORD_TERMINATE;
00774       ast_mutex_unlock(&conflock);
00775       while (1) {
00776          ast_mutex_lock(&conflock);
00777          if (conf->recording == MEETME_RECORD_OFF)
00778             break;
00779          ast_mutex_unlock(&conflock);
00780       }
00781    }
00782 
00783    if (conf->chan)
00784       ast_hangup(conf->chan);
00785    else
00786       close(conf->fd);
00787    
00788    free(conf);
00789 
00790    return 0;
00791 }

static void conf_play struct ast_channel chan,
struct ast_conference conf,
int  sound
[static]
 

Definition at line 403 of file app_meetme.c.

References ast_channel::_softhangup, ast_autoservice_start(), ast_autoservice_stop(), ast_mutex_lock(), ast_mutex_unlock(), careful_write(), enter, ENTER, ast_conference::fd, leave, and LEAVE.

Referenced by conf_run().

00404 {
00405    unsigned char *data;
00406    int len;
00407    int res = -1;
00408 
00409    if (!chan->_softhangup)
00410       res = ast_autoservice_start(chan);
00411 
00412    ast_mutex_lock(&conflock);
00413 
00414    switch(sound) {
00415    case ENTER:
00416       data = enter;
00417       len = sizeof(enter);
00418       break;
00419    case LEAVE:
00420       data = leave;
00421       len = sizeof(leave);
00422       break;
00423    default:
00424       data = NULL;
00425       len = 0;
00426    }
00427    if (data) 
00428       careful_write(conf->fd, data, len, 1);
00429 
00430    ast_mutex_unlock(&conflock);
00431 
00432    if (!res) 
00433       ast_autoservice_stop(chan);
00434 }

static int conf_run struct ast_channel chan,
struct ast_conference conf,
int  confflags
[static]
 

Definition at line 793 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, ast_conf_user::adminflags, app, ast_channel_setoption(), ast_config_AST_SPOOL_DIR, AST_DIGIT_ANY, ast_dsp_free(), ast_dsp_new(), ast_dsp_silence(), ast_filedelete(), ast_fileexists(), AST_FORMAT_SLINEAR, ast_frame_adjust_volume(), AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree(), AST_FRIENDLY_OFFSET, ast_goto_if_exists(), ast_indicate(), ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), AST_OPTION_TONE_VERIFY, ast_pthread_create, ast_read(), ast_record_review(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitfor_nandfds(), ast_waitstream(), ast_write(), ast_conference::attr, audio_buffers, calloc, careful_write(), ast_conference::chan, ast_conf_user::chan, conf_flush(), conf_free(), conf_play(), CONF_SIZE, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROUSER, CONFFLAG_MARKEDEXIT, CONFFLAG_MARKEDUSER, CONFFLAG_MOH, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_POUNDEXIT, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_STARMENU, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, ast_channel::context, dsp, ENTER, EVENT_FLAG_CALL, exitcontext, ast_channel::fds, ast_conference::firstuser, ast_frame::frametype, free, ast_channel::language, ast_conference::lastuser, LEAVE, ast_conference::locked, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, manager_event(), ast_conference::markedusers, MEETME_DELAYDETECTENDTALK, MEETME_DELAYDETECTTALK, MEETME_RECORD_ACTIVE, ast_channel::name, ast_conf_user::nextuser, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), ast_conf_user::prevuser, ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, recordthread(), ast_conference::recordthread, reset_volumes(), set_talk_volume(), ast_frame::subclass, tweak_listen_volume(), tweak_talk_volume(), ast_channel::type, ast_channel::uniqueid, user, ast_conf_user::user_no, ast_conf_user::userflags, ast_conference::users, VERBOSE_PREFIX_4, VOL_DOWN, VOL_UP, and ast_conference::zapconf.

Referenced by conf_exec().

00794 {
00795    struct ast_conf_user *user = calloc(1, sizeof(*user));
00796    struct ast_conf_user *usr = NULL;
00797    int fd;
00798    struct zt_confinfo ztc, ztc_empty;
00799    struct ast_frame *f;
00800    struct ast_channel *c;
00801    struct ast_frame fr;
00802    int outfd;
00803    int ms;
00804    int nfds;
00805    int res;
00806    int flags;
00807    int retryzap;
00808    int origfd;
00809    int musiconhold = 0;
00810    int firstpass = 0;
00811    int lastmarked = 0;
00812    int currentmarked = 0;
00813    int ret = -1;
00814    int x;
00815    int menu_active = 0;
00816    int using_pseudo = 0;
00817    int duration=20;
00818    struct ast_dsp *dsp=NULL;
00819    struct ast_app *app;
00820    char *agifile;
00821    char *agifiledefault = "conf-background.agi";
00822    char meetmesecs[30] = "";
00823    char exitcontext[AST_MAX_CONTEXT] = "";
00824    char recordingtmp[AST_MAX_EXTENSION] = "";
00825    int dtmf;
00826    ZT_BUFFERINFO bi;
00827    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
00828    char *buf = __buf + AST_FRIENDLY_OFFSET;
00829    
00830    if (!user) {
00831       ast_log(LOG_ERROR, "Out of memory\n");
00832       return ret;
00833    }
00834 
00835    if (confflags & CONFFLAG_RECORDCONF && conf->recording !=MEETME_RECORD_ACTIVE) {
00836       conf->recordingfilename = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE");
00837       if (!conf->recordingfilename) {
00838          snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
00839          conf->recordingfilename = ast_strdupa(recordingtmp);
00840       }
00841       conf->recordingformat = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT");
00842       if (!conf->recordingformat) {
00843          snprintf(recordingtmp, sizeof(recordingtmp), "wav");
00844          conf->recordingformat = ast_strdupa(recordingtmp);
00845       }
00846       pthread_attr_init(&conf->attr);
00847       pthread_attr_setdetachstate(&conf->attr, PTHREAD_CREATE_DETACHED);
00848       ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n",
00849              conf->confno, conf->recordingfilename, conf->recordingformat);
00850       ast_pthread_create(&conf->recordthread, &conf->attr, recordthread, conf);
00851    }
00852 
00853    time(&user->jointime);
00854 
00855    if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
00856       /* Sorry, but this confernce is locked! */   
00857       if (!ast_streamfile(chan, "conf-locked", chan->language))
00858          ast_waitstream(chan, "");
00859       goto outrun;
00860    }
00861 
00862    if (confflags & CONFFLAG_MARKEDUSER)
00863       conf->markedusers++;
00864       
00865       ast_mutex_lock(&conflock);
00866    if (!conf->firstuser) {
00867       /* Fill the first new User struct */
00868       user->user_no = 1;
00869       conf->firstuser = user;
00870       conf->lastuser = user;
00871    } else {
00872       /* Fill the new user struct */   
00873       user->user_no = conf->lastuser->user_no + 1; 
00874       user->prevuser = conf->lastuser;
00875       if (conf->lastuser->nextuser) {
00876          ast_log(LOG_WARNING, "Error in User Management!\n");
00877          ast_mutex_unlock(&conflock);
00878          goto outrun;
00879       } else {
00880          conf->lastuser->nextuser = user;
00881          conf->lastuser = user;
00882       }
00883    }
00884 
00885    user->chan = chan;
00886    user->userflags = confflags;
00887    user->adminflags = 0;
00888    user->talking = -1;
00889    conf->users++;
00890    ast_mutex_unlock(&conflock);
00891 
00892    if (confflags & CONFFLAG_EXIT_CONTEXT) {
00893       if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) 
00894          ast_copy_string(exitcontext, agifile, sizeof(exitcontext));
00895       else if (!ast_strlen_zero(chan->macrocontext)) 
00896          ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
00897       else
00898          ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
00899    }
00900 
00901    if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER)) {
00902       snprintf(user->namerecloc, sizeof(user->namerecloc),
00903           "%s/meetme/meetme-username-%s-%d", ast_config_AST_SPOOL_DIR,
00904           conf->confno, user->user_no);
00905       res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
00906       if (res == -1)
00907          goto outrun;
00908    }
00909 
00910    if (!(confflags & CONFFLAG_QUIET)) {
00911       if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
00912          if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
00913             ast_waitstream(chan, "");
00914       if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
00915          if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
00916             ast_waitstream(chan, "");
00917    }
00918 
00919    if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
00920       int keepplaying = 1;
00921 
00922       if (conf->users == 2) { 
00923          if (!ast_streamfile(chan,"conf-onlyone",chan->language)) {
00924             res = ast_waitstream(chan, AST_DIGIT_ANY);
00925             if (res > 0)
00926                keepplaying=0;
00927             else if (res == -1)
00928                goto outrun;
00929          }
00930       } else { 
00931          if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
00932             res = ast_waitstream(chan, AST_DIGIT_ANY);
00933             if (res > 0)
00934                keepplaying=0;
00935             else if (res == -1)
00936                goto outrun;
00937          }
00938          if (keepplaying) {
00939             res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
00940             if (res > 0)
00941                keepplaying=0;
00942             else if (res == -1)
00943                goto outrun;
00944          }
00945          if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
00946             res = ast_waitstream(chan, AST_DIGIT_ANY);
00947             if (res > 0)
00948                keepplaying=0;
00949             else if (res == -1) 
00950                goto outrun;
00951          }
00952       }
00953    }
00954 
00955    ast_indicate(chan, -1);
00956 
00957    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00958       ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
00959       goto outrun;
00960    }
00961 
00962    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
00963       ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
00964       goto outrun;
00965    }
00966 
00967    retryzap = strcasecmp(chan->type, "Zap");
00968    user->zapchannel = !retryzap;
00969 
00970  zapretry:
00971    origfd = chan->fds[0];
00972    if (retryzap) {
00973       fd = open("/dev/zap/pseudo", O_RDWR);
00974       if (fd < 0) {
00975          ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
00976          goto outrun;
00977       }
00978       using_pseudo = 1;
00979       /* Make non-blocking */
00980       flags = fcntl(fd, F_GETFL);
00981       if (flags < 0) {
00982          ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
00983          close(fd);
00984          goto outrun;
00985       }
00986       if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
00987          ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
00988          close(fd);
00989          goto outrun;
00990       }
00991       /* Setup buffering information */
00992       memset(&bi, 0, sizeof(bi));
00993       bi.bufsize = CONF_SIZE/2;
00994       bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
00995       bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
00996       bi.numbufs = audio_buffers;
00997       if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
00998          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
00999          close(fd);
01000          goto outrun;
01001       }
01002       x = 1;
01003       if (ioctl(fd, ZT_SETLINEAR, &x)) {
01004          ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
01005          close(fd);
01006          goto outrun;
01007       }
01008       nfds = 1;
01009    } else {
01010       /* XXX Make sure we're not running on a pseudo channel XXX */
01011       fd = chan->fds[0];
01012       nfds = 0;
01013    }
01014    memset(&ztc, 0, sizeof(ztc));
01015    memset(&ztc_empty, 0, sizeof(ztc_empty));
01016    /* Check to see if we're in a conference... */
01017    ztc.chan = 0;  
01018    if (ioctl(fd, ZT_GETCONF, &ztc)) {
01019       ast_log(LOG_WARNING, "Error getting conference\n");
01020       close(fd);
01021       goto outrun;
01022    }
01023    if (ztc.confmode) {
01024       /* Whoa, already in a conference...  Retry... */
01025       if (!retryzap) {
01026          ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
01027          retryzap = 1;
01028          goto zapretry;
01029       }
01030    }
01031    memset(&ztc, 0, sizeof(ztc));
01032    /* Add us to the conference */
01033    ztc.chan = 0;  
01034    ztc.confno = conf->zapconf;
01035 
01036    ast_mutex_lock(&conflock);
01037 
01038    if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER) && conf->users > 1) {
01039       if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) {
01040          if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
01041             ast_waitstream(conf->chan, "");
01042          if (!ast_streamfile(conf->chan, "conf-hasjoin", chan->language))
01043             ast_waitstream(conf->chan, "");
01044       }
01045    }
01046 
01047    if (confflags & CONFFLAG_MONITOR)
01048       ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
01049    else if (confflags & CONFFLAG_TALKER)
01050       ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
01051    else 
01052       ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
01053 
01054    if (ioctl(fd, ZT_SETCONF, &ztc)) {
01055       ast_log(LOG_WARNING, "Error setting conference\n");
01056       close(fd);
01057       ast_mutex_unlock(&conflock);
01058       goto outrun;
01059    }
01060    ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf);
01061 
01062    manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
01063             "Channel: %s\r\n"
01064             "Uniqueid: %s\r\n"
01065             "Meetme: %s\r\n"
01066             "Usernum: %d\r\n",
01067             chan->name, chan->uniqueid, conf->confno, user->user_no);
01068 
01069    if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
01070       firstpass = 1;
01071       if (!(confflags & CONFFLAG_QUIET))
01072          if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
01073             conf_play(chan, conf, ENTER);
01074    }
01075 
01076    ast_mutex_unlock(&conflock);
01077 
01078    conf_flush(fd, chan);
01079 
01080    if (confflags & CONFFLAG_AGI) {
01081       /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
01082          or use default filename of conf-background.agi */
01083 
01084       agifile = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND");
01085       if (!agifile)
01086          agifile = agifiledefault;
01087 
01088       if (user->zapchannel) {
01089          /*  Set CONFMUTE mode on Zap channel to mute DTMF tones */
01090          x = 1;
01091          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01092       }
01093       /* Find a pointer to the agi app and execute the script */
01094       app = pbx_findapp("agi");
01095       if (app) {
01096          ret = pbx_exec(chan, app, agifile, 1);
01097       } else {
01098          ast_log(LOG_WARNING, "Could not find application (agi)\n");
01099          ret = -2;
01100       }
01101       if (user->zapchannel) {
01102          /*  Remove CONFMUTE mode on Zap channel */
01103          x = 0;
01104          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01105       }
01106    } else {
01107       if (user->zapchannel && (confflags & CONFFLAG_STARMENU)) {
01108          /*  Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
01109          x = 1;
01110          ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01111       }  
01112       if (confflags & CONFFLAG_MONITORTALKER && !(dsp = ast_dsp_new())) {
01113          ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
01114          res = -1;
01115       }
01116       for(;;) {
01117          int menu_was_active = 0;
01118 
01119          outfd = -1;
01120          ms = -1;
01121          
01122          /* if we have just exited from the menu, and the user had a channel-driver
01123             volume adjustment, restore it
01124          */
01125          if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
01126             set_talk_volume(user, user->listen.desired);
01127 
01128          menu_was_active = menu_active;
01129 
01130          currentmarked = conf->markedusers;
01131          if (!(confflags & CONFFLAG_QUIET) &&
01132              (confflags & CONFFLAG_MARKEDUSER) &&
01133              (confflags & CONFFLAG_WAITMARKED) &&
01134              lastmarked == 0) {
01135             if (currentmarked == 1 && conf->users > 1) {
01136                ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
01137                if (conf->users - 1 == 1) {
01138                   if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
01139                      ast_waitstream(chan, "");
01140                } else {
01141                   if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
01142                      ast_waitstream(chan, "");
01143                }
01144             }
01145             if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
01146                if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
01147                   ast_waitstream(chan, "");
01148          }
01149 
01150          c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
01151          
01152          /* Update the struct with the actual confflags */
01153          user->userflags = confflags;
01154          
01155          if (confflags & CONFFLAG_WAITMARKED) {
01156             if(currentmarked == 0) {
01157                if (lastmarked != 0) {
01158                   if (!(confflags & CONFFLAG_QUIET))
01159                      if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
01160                         ast_waitstream(chan, "");
01161                   if(confflags & CONFFLAG_MARKEDEXIT)
01162                      break;
01163                   else {
01164                      ztc.confmode = ZT_CONF_CONF;
01165                      if (ioctl(fd, ZT_SETCONF, &ztc)) {
01166                         ast_log(LOG_WARNING, "Error setting conference\n");
01167                         close(fd);
01168                         goto outrun;
01169                      }
01170                   }
01171                }
01172                if (musiconhold == 0 && (confflags & CONFFLAG_MOH)) {
01173                   ast_moh_start(chan, NULL);
01174                   musiconhold = 1;
01175                } else {
01176                   ztc.confmode = ZT_CONF_CONF;
01177                   if (ioctl(fd, ZT_SETCONF, &ztc)) {
01178                      ast_log(LOG_WARNING, "Error setting conference\n");
01179                      close(fd);
01180                      goto outrun;
01181                   }
01182                }
01183             } else if(currentmarked >= 1 && lastmarked == 0) {
01184                if (confflags & CONFFLAG_MONITOR)
01185                   ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
01186                else if (confflags & CONFFLAG_TALKER)
01187                   ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
01188                else
01189                   ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
01190                if (ioctl(fd, ZT_SETCONF, &ztc)) {
01191                   ast_log(LOG_WARNING, "Error setting conference\n");
01192                   close(fd);
01193                   goto outrun;
01194                }
01195                if (musiconhold && (confflags & CONFFLAG_MOH)) {
01196                   ast_moh_stop(chan);
01197                   musiconhold = 0;
01198                }
01199                if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
01200                   if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
01201                      ast_waitstream(chan, "");
01202                   conf_play(chan, conf, ENTER);
01203                }
01204             }
01205          }
01206 
01207          /* trying to add moh for single person conf */
01208          if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
01209             if (conf->users == 1) {
01210                if (musiconhold == 0) {
01211                   ast_moh_start(chan, NULL);
01212                   musiconhold = 1;
01213                } 
01214             } else {
01215                if (musiconhold) {
01216                   ast_moh_stop(chan);
01217                   musiconhold = 0;
01218                }
01219             }
01220          }
01221          
01222          /* Leave if the last marked user left */
01223          if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
01224             ret = -1;
01225             break;
01226          }
01227    
01228          /* Check if the admin changed my modes */
01229          if (user->adminflags) {       
01230             /* Set the new modes */
01231             if ((user->adminflags & ADMINFLAG_MUTED) && (ztc.confmode & ZT_CONF_TALKER)) {
01232                ztc.confmode ^= ZT_CONF_TALKER;
01233                if (ioctl(fd, ZT_SETCONF, &ztc)) {
01234                   ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01235                   ret = -1;
01236                   break;
01237                }
01238             }
01239             if (!(user->adminflags & ADMINFLAG_MUTED) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
01240                ztc.confmode |= ZT_CONF_TALKER;
01241                if (ioctl(fd, ZT_SETCONF, &ztc)) {
01242                   ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01243                   ret = -1;
01244                   break;
01245                }
01246             }
01247             if (user->adminflags & ADMINFLAG_KICKME) {
01248                /* You have been kicked. */
01249                if (!ast_streamfile(chan, "conf-kicked", chan->language))
01250                   ast_waitstream(chan, "");
01251                ret = 0;
01252                break;
01253             }
01254          } else if (!(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
01255             ztc.confmode |= ZT_CONF_TALKER;
01256             if (ioctl(fd, ZT_SETCONF, &ztc)) {
01257                ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01258                ret = -1;
01259                break;
01260             }
01261          }
01262 
01263          if (c) {
01264             if (c->fds[0] != origfd) {
01265                if (using_pseudo) {
01266                   /* Kill old pseudo */
01267                   close(fd);
01268                   using_pseudo = 0;
01269                }
01270                ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
01271                retryzap = strcasecmp(c->type, "Zap");
01272                user->zapchannel = !retryzap;
01273                goto zapretry;
01274             }
01275             f = ast_read(c);
01276             if (!f)
01277                break;
01278             if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
01279                if (user->talk.actual)
01280                   ast_frame_adjust_volume(f, user->talk.actual);
01281 
01282                if (confflags &  CONFFLAG_MONITORTALKER) {
01283                   int totalsilence;
01284 
01285                   if (user->talking == -1)
01286                      user->talking = 0;
01287 
01288                   res = ast_dsp_silence(dsp, f, &totalsilence);
01289                   if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
01290                      user->talking = 1;
01291                      manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
01292                               "Channel: %s\r\n"
01293                               "Uniqueid: %s\r\n"
01294                               "Meetme: %s\r\n"
01295                               "Usernum: %d\r\n",
01296                               chan->name, chan->uniqueid, conf->confno, user->user_no);
01297                   }
01298                   if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
01299                      user->talking = 0;
01300                      manager_event(EVENT_FLAG_CALL, "MeetmeStopTalking",
01301                               "Channel: %s\r\n"
01302                               "Uniqueid: %s\r\n"
01303                               "Meetme: %s\r\n"
01304                               "Usernum: %d\r\n",
01305                               chan->name, chan->uniqueid, conf->confno, user->user_no);
01306                   }
01307                }
01308                if (using_pseudo) {
01309                   /* Absolutely do _not_ use careful_write here...
01310                      it is important that we read data from the channel
01311                      as fast as it arrives, and feed it into the conference.
01312                      The buffering in the pseudo channel will take care of any
01313                      timing differences, unless they are so drastic as to lose
01314                      audio frames (in which case carefully writing would only
01315                      have delayed the audio even further).
01316                   */
01317                   /* As it turns out, we do want to use careful write.  We just
01318                      don't want to block, but we do want to at least *try*
01319                      to write out all the samples.
01320                    */
01321                   careful_write(fd, f->data, f->datalen, 0);
01322                }
01323             } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
01324                char tmp[2];
01325 
01326                tmp[0] = f->subclass;
01327                tmp[1] = '\0';
01328                if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
01329                   ret = 0;
01330                   ast_frfree(f);
01331                   break;
01332                } else if (option_debug > 1)
01333                   ast_log(LOG_DEBUG, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp, exitcontext);
01334             } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
01335                ret = 0;
01336                ast_frfree(f);
01337                break;
01338             } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
01339                if (ioctl(fd, ZT_SETCONF, &ztc_empty)) {
01340                   ast_log(LOG_WARNING, "Error setting conference\n");
01341                   close(fd);
01342                   ast_frfree(f);
01343                   goto outrun;
01344                }
01345 
01346                /* if we are entering the menu, and the user has a channel-driver
01347                   volume adjustment, clear it
01348                */
01349                if (!menu_active && user->talk.desired && !user->talk.actual)
01350                   set_talk_volume(user, 0);
01351 
01352                if (musiconhold) {
01353                      ast_moh_stop(chan);
01354                }
01355                if ((confflags & CONFFLAG_ADMIN)) {
01356                   /* Admin menu */
01357                   if (!menu_active) {
01358                      menu_active = 1;
01359                      /* Record this sound! */
01360                      if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
01361                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
01362                         ast_stopstream(chan);
01363                      } else 
01364                         dtmf = 0;
01365                   } else 
01366                      dtmf = f->subclass;
01367                   if (dtmf) {
01368                      switch(dtmf) {
01369                      case '1': /* Un/Mute */
01370                         menu_active = 0;
01371                         if (ztc.confmode & ZT_CONF_TALKER) {
01372                                  ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
01373                                  confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
01374                         } else {
01375                            ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
01376                            confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
01377                         }
01378                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
01379                            ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01380                            ret = -1;
01381                            break;
01382                         }
01383                         if (ztc.confmode & ZT_CONF_TALKER) {
01384                            if (!ast_streamfile(chan, "conf-unmuted", chan->language))
01385                               ast_waitstream(chan, "");
01386                         } else {
01387                            if (!ast_streamfile(chan, "conf-muted", chan->language))
01388                               ast_waitstream(chan, "");
01389                         }
01390                         break;
01391                      case '2': /* Un/Lock the Conference */
01392                         menu_active = 0;
01393                         if (conf->locked) {
01394                            conf->locked = 0;
01395                            if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
01396                               ast_waitstream(chan, "");
01397                         } else {
01398                            conf->locked = 1;
01399                            if (!ast_streamfile(chan, "conf-lockednow", chan->language))
01400                               ast_waitstream(chan, "");
01401                         }
01402                         break;
01403                      case '3': /* Eject last user */
01404                         menu_active = 0;
01405                         usr = conf->lastuser;
01406                         if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
01407                            if(!ast_streamfile(chan, "conf-errormenu", chan->language))
01408                               ast_waitstream(chan, "");
01409                         } else 
01410                            usr->adminflags |= ADMINFLAG_KICKME;
01411                         ast_stopstream(chan);
01412                         break;   
01413                      case '4':
01414                         tweak_listen_volume(user, VOL_DOWN);
01415                         break;
01416                      case '6':
01417                         tweak_listen_volume(user, VOL_UP);
01418                         break;
01419                      case '7':
01420                         tweak_talk_volume(user, VOL_DOWN);
01421                         break;
01422                      case '8':
01423                         menu_active = 0;
01424                         break;
01425                      case '9':
01426                         tweak_talk_volume(user, VOL_UP);
01427                         break;
01428                      default:
01429                         menu_active = 0;
01430                         /* Play an error message! */
01431                         if (!ast_streamfile(chan, "conf-errormenu", chan->language))
01432                            ast_waitstream(chan, "");
01433                         break;
01434                      }
01435                   }
01436                } else {
01437                   /* User menu */
01438                   if (!menu_active) {
01439                      menu_active = 1;
01440                      if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
01441                         dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
01442                         ast_stopstream(chan);
01443                      } else
01444                         dtmf = 0;
01445                   } else 
01446                      dtmf = f->subclass;
01447                   if (dtmf) {
01448                      switch(dtmf) {
01449                      case '1': /* Un/Mute */
01450                         menu_active = 0;
01451                         if (ztc.confmode & ZT_CONF_TALKER) {
01452                                  ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
01453                                  confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
01454                         } else if (!(user->adminflags & ADMINFLAG_MUTED)) {
01455                            ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
01456                            confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
01457                         }
01458                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
01459                            ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01460                            ret = -1;
01461                            break;
01462                         }
01463                         if (ztc.confmode & ZT_CONF_TALKER) {
01464                            if (!ast_streamfile(chan, "conf-unmuted", chan->language))
01465                               ast_waitstream(chan, "");
01466                         } else {
01467                            if (!ast_streamfile(chan, "conf-muted", chan->language))
01468                               ast_waitstream(chan, "");
01469                         }
01470                         break;
01471                      case '4':
01472                         tweak_listen_volume(user, VOL_DOWN);
01473                         break;
01474                      case '6':
01475                         tweak_listen_volume(user, VOL_UP);
01476                         break;
01477                      case '7':
01478                         tweak_talk_volume(user, VOL_DOWN);
01479                         break;
01480                      case '8':
01481                         menu_active = 0;
01482                         break;
01483                      case '9':
01484                         tweak_talk_volume(user, VOL_UP);
01485                         break;
01486                      default:
01487                         menu_active = 0;
01488                         if (!ast_streamfile(chan, "conf-errormenu", chan->language))
01489                            ast_waitstream(chan, "");
01490                         break;
01491                      }
01492                   }
01493                }
01494                if (musiconhold)
01495                      ast_moh_start(chan, NULL);
01496 
01497                if (ioctl(fd, ZT_SETCONF, &ztc)) {
01498                   ast_log(LOG_WARNING, "Error setting conference\n");
01499                   close(fd);
01500                   ast_frfree(f);
01501                   goto outrun;
01502                }
01503 
01504                conf_flush(fd, chan);
01505             } else if (option_debug) {
01506                ast_log(LOG_DEBUG,
01507                   "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
01508                   chan->name, f->frametype, f->subclass);
01509             }
01510             ast_frfree(f);
01511          } else if (outfd > -1) {
01512             res = read(outfd, buf, CONF_SIZE);
01513             if (res > 0) {
01514                memset(&fr, 0, sizeof(fr));
01515                fr.frametype = AST_FRAME_VOICE;
01516                fr.subclass = AST_FORMAT_SLINEAR;
01517                fr.datalen = res;
01518                fr.samples = res/2;
01519                fr.data = buf;
01520                fr.offset = AST_FRIENDLY_OFFSET;
01521                if (user->listen.actual)
01522                   ast_frame_adjust_volume(&fr, user->listen.actual);
01523                if (ast_write(chan, &fr) < 0) {
01524                   ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
01525                }
01526             } else 
01527                ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
01528          }
01529          lastmarked = currentmarked;
01530       }
01531    }
01532 
01533    if (musiconhold)
01534       ast_moh_stop(chan);
01535    
01536    if (using_pseudo)
01537       close(fd);
01538    else {
01539       /* Take out of conference */
01540       ztc.chan = 0;  
01541       ztc.confno = 0;
01542       ztc.confmode = 0;
01543       if (ioctl(fd, ZT_SETCONF, &ztc)) {
01544          ast_log(LOG_WARNING, "Error setting conference\n");
01545       }
01546    }
01547 
01548    reset_volumes(user);
01549 
01550    ast_mutex_lock(&conflock);
01551    if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
01552       conf_play(chan, conf, LEAVE);
01553 
01554    if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER)) {
01555       if (ast_fileexists(user->namerecloc, NULL, NULL)) {
01556          if ((conf->chan) && (conf->users > 1)) {
01557             if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
01558                ast_waitstream(conf->chan, "");
01559             if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language))
01560                ast_waitstream(conf->chan, "");
01561          }
01562          ast_filedelete(user->namerecloc, NULL);
01563       }
01564    }
01565    ast_mutex_unlock(&conflock);
01566 
01567  outrun:
01568    ast_mutex_lock(&conflock);
01569 
01570    if (confflags & CONFFLAG_MONITORTALKER && dsp)
01571       ast_dsp_free(dsp);
01572    
01573    if (user->user_no) { /* Only cleanup users who really joined! */
01574       manager_event(EVENT_FLAG_CALL, "MeetmeLeave", 
01575                "Channel: %s\r\n"
01576                "Uniqueid: %s\r\n"
01577                "Meetme: %s\r\n"
01578                "Usernum: %d\r\n",
01579                chan->name, chan->uniqueid, conf->confno, user->user_no);
01580       conf->users--;
01581       if (confflags & CONFFLAG_MARKEDUSER) 
01582          conf->markedusers--;
01583       if (!conf->users) {
01584          /* No more users -- close this one out */
01585          conf_free(conf);
01586       } else {
01587          /* Remove the user struct */ 
01588          if (user == conf->firstuser) {
01589             if (user->nextuser) {
01590                /* There is another entry */
01591                user->nextuser->prevuser = NULL;
01592             } else {
01593                /* We are the only entry */
01594                conf->lastuser = NULL;
01595             }
01596             /* In either case */
01597             conf->firstuser = user->nextuser;
01598          } else if (user == conf->lastuser){
01599             if (user->prevuser)
01600                user->prevuser->nextuser = NULL;
01601             else
01602                ast_log(LOG_ERROR, "Bad bad bad!  We're the last, not the first, but nobody before us??\n");
01603             conf->lastuser = user->prevuser;
01604          } else {
01605             if (user->nextuser)
01606                user->nextuser->prevuser = user->prevuser;
01607             else
01608                ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n");
01609             if (user->prevuser)
01610                user->prevuser->nextuser = user->nextuser;
01611             else
01612                ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n");
01613          }
01614       }
01615       /* Return the number of seconds the user was in the conf */
01616       snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
01617       pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
01618    }
01619    free(user);
01620    ast_mutex_unlock(&conflock);
01621 
01622    return ret;
01623 }

static int confs_show int  fd,
int  argc,
char **  argv
[static]
 

Definition at line 503 of file app_meetme.c.

References ast_cli(), and RESULT_SUCCESS.

00504 {
00505    ast_cli(fd, "Deprecated! Please use 'meetme' instead.\n");
00506 
00507    return RESULT_SUCCESS;
00508 }

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

Definition at line 1720 of file app_meetme.c.

References ast_channel::_state, ast_answer(), ast_log(), ast_say_number(), AST_STATE_UP, ast_strdupa, ast_strlen_zero(), find_conf(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_WARNING, pbx_builtin_setvar_helper(), strsep(), and ast_conference::users.

Referenced by load_module().

01721 {
01722    struct localuser *u;
01723    int res = 0;
01724    struct ast_conference *conf;
01725    int count;
01726    char *confnum, *localdata;
01727    char val[80] = "0"; 
01728 
01729    if (ast_strlen_zero(data)) {
01730       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
01731       return -1;
01732    }
01733 
01734    LOCAL_USER_ADD(u);
01735    
01736    localdata = ast_strdupa(data);
01737    if (!localdata) {
01738       ast_log(LOG_ERROR, "Out of memory!\n");
01739       LOCAL_USER_REMOVE(u);
01740       return -1;
01741    }
01742    
01743    confnum = strsep(&localdata,"|");       
01744    conf = find_conf(chan, confnum, 0, 0, NULL, NULL);
01745    if (conf)
01746       count = conf->users;
01747    else
01748       count = 0;
01749 
01750    if (!ast_strlen_zero(localdata)){
01751       /* have var so load it and exit */
01752       snprintf(val, sizeof(val), "%d",count);
01753       pbx_builtin_setvar_helper(chan, localdata, val);
01754    } else {
01755       if (chan->_state != AST_STATE_UP)
01756          ast_answer(chan);
01757       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
01758    }
01759    LOCAL_USER_REMOVE(u);
01760 
01761    return res;
01762 }

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 2261 of file app_meetme.c.

References tdesc.

02262 {
02263    return (char *) tdesc;
02264 }

static struct ast_conference* find_conf struct ast_channel chan,
char *  confno,
int  make,
int  dynamic,
char *  dynamic_pin,
struct ast_flags confflags
[static]
 

Definition at line 1625 of file app_meetme.c.

References ast_app_getdata(), ast_clear_flag, ast_config_destroy(), ast_config_load(), ast_log(), AST_MAX_EXTENSION, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_test_flag, ast_variable_browse(), build_conf(), cfg, ast_conference::chan, CONFFLAG_INTROUSER, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFIG_FILE_NAME, ast_conference::confno, confs, LOG_DEBUG, LOG_WARNING, ast_variable::name, ast_variable::next, ast_conference::next, ast_conference::pin, ast_conference::pinadmin, strsep(), ast_variable::value, and var.

Referenced by conf_exec(), and count_exec().

01627 {
01628    struct ast_config *cfg;
01629    struct ast_variable *var;
01630    struct ast_conference *cnf;
01631 
01632    /* Check first in the conference list */
01633    ast_mutex_lock(&conflock);
01634    for (cnf = confs; cnf; cnf = cnf->next) {
01635       if (!strcmp(confno, cnf->confno)) 
01636          break;
01637    }
01638    ast_mutex_unlock(&conflock);
01639 
01640    if (!cnf) {
01641       if (dynamic) {
01642          /* No need to parse meetme.conf */
01643          ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
01644          if (dynamic_pin) {
01645             if (dynamic_pin[0] == 'q') {
01646                /* Query the user to enter a PIN */
01647                if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, AST_MAX_EXTENSION - 1, 0) < 0)
01648                   return NULL;
01649             }
01650             cnf = build_conf(confno, dynamic_pin, "", make, dynamic);
01651          } else {
01652             cnf = build_conf(confno, "", "", make, dynamic);
01653          }
01654       } else {
01655          /* Check the config */
01656          cfg = ast_config_load(CONFIG_FILE_NAME);
01657          if (!cfg) {
01658             ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
01659             return NULL;
01660          }
01661          var = ast_variable_browse(cfg, "rooms");
01662          while (var) {
01663             if (!strcasecmp(var->name, "conf")) {
01664                /* Separate the PIN */
01665                char *pin, *pinadmin, *conf;
01666 
01667                if ((pinadmin = ast_strdupa(var->value))) {
01668                   conf = strsep(&pinadmin, "|,");
01669                   pin = strsep(&pinadmin, "|,");
01670                   if (!strcasecmp(conf, confno)) {
01671                      /* Bingo it's a valid conference */
01672                      if (pin)
01673                         if (pinadmin)
01674                            cnf = build_conf(confno, pin, pinadmin, make, dynamic);
01675                         else
01676                            cnf = build_conf(confno, pin, "", make, dynamic);
01677                      else
01678                         if (pinadmin)
01679                            cnf = build_conf(confno, "", pinadmin, make, dynamic);
01680                         else
01681                            cnf = build_conf(confno, "", "", make, dynamic);
01682                      break;
01683                   }
01684                }
01685             }
01686             var = var->next;
01687          }
01688          if (!var) {
01689             ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
01690          }
01691          ast_config_destroy(cfg);
01692       }
01693    } else if (dynamic_pin) {
01694       /* Correct for the user selecting 'D' instead of 'd' to have
01695          someone join into a conference that has already been created
01696          with a pin. */
01697       if (dynamic_pin[0] == 'q')
01698          dynamic_pin[0] = '\0';
01699    }
01700 
01701    if (cnf) {
01702       if (confflags && !cnf->chan &&
01703           !ast_test_flag(confflags, CONFFLAG_QUIET) &&
01704           ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
01705          ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
01706          ast_clear_flag(confflags, CONFFLAG_INTROUSER);
01707       }
01708       
01709       if (confflags && !cnf->chan &&
01710           ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
01711          ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
01712          ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
01713       }
01714    }
01715 
01716    return cnf;
01717 }

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

Definition at line 2017 of file app_meetme.c.

References ast_conference::firstuser, ast_conf_user::nextuser, user, and ast_conf_user::user_no.

02018 {
02019    struct ast_conf_user *user = NULL;
02020    int cid;
02021 
02022    if (!conf || !callerident) {
02023       return NULL;
02024    }
02025 
02026    sscanf(callerident, "%i", &cid);
02027 
02028    user = conf->firstuser;
02029    while (user) {
02030       if (user->user_no == cid)
02031          break;
02032       user = user->nextuser;
02033    }
02034 
02035    return user;
02036 }

static char* istalking int  x  )  [static]
 

Definition at line 255 of file app_meetme.c.

Referenced by conf_cmd().

00256 {
00257    if (x > 0)
00258       return "(talking)";
00259    else if (x < 0)
00260       return "(unmonitored)";
00261    else 
00262       return "(not talking)";
00263 }

char* key void   ) 
 

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

 char *key(void) {
         return ASTERISK_GPL_KEY;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 2275 of file app_meetme.c.

References ASTERISK_GPL_KEY.

02276 {
02277    return ASTERISK_GPL_KEY;
02278 }

static void load_config void   )  [static]
 

Definition at line 2198 of file app_meetme.c.

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

02199 {
02200    struct ast_config *cfg;
02201    char *val;
02202 
02203    audio_buffers = DEFAULT_AUDIO_BUFFERS;
02204 
02205    if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
02206       return;
02207 
02208    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
02209       if ((sscanf(val, "%d", &audio_buffers) != 1)) {
02210          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
02211          audio_buffers = DEFAULT_AUDIO_BUFFERS;
02212       } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) {
02213          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
02214             ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS);
02215          audio_buffers = DEFAULT_AUDIO_BUFFERS;
02216       }
02217       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
02218          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
02219    }
02220 
02221    ast_config_destroy(cfg);
02222 }

int load_module void   ) 
 

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 2239 of file app_meetme.c.

References admin_exec(), app, app2, app3, ast_cli_register(), ast_register_application(), conf_exec(), count_exec(), descrip, descrip2, descrip3, load_config(), synopsis, synopsis2, and synopsis3.

02240 {
02241    int res;
02242 
02243    load_config();
02244 
02245    res = ast_cli_register(&cli_show_confs);
02246    res |= ast_cli_register(&cli_conf);
02247    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
02248    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
02249    res |= ast_register_application(app, conf_exec, synopsis, descrip);
02250 
02251    return res;
02252 }

static void * recordthread void *  args  )  [static]
 

Definition at line 2155 of file app_meetme.c.

References ast_closestream(), AST_FRAME_VOICE, ast_frfree(), ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_stopstream(), ast_waitfor(), ast_writefile(), ast_writestream(), ast_conference::chan, ast_frame::frametype, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, and s.

Referenced by conf_run().

02156 {
02157    struct ast_conference *cnf = args;
02158    struct ast_frame *f=NULL;
02159    int flags;
02160    struct ast_filestream *s;
02161    int res=0;
02162 
02163    if (!cnf || !cnf->chan) {
02164       pthread_exit(0);
02165    }
02166    ast_stopstream(cnf->chan);
02167    flags = O_CREAT|O_TRUNC|O_WRONLY;
02168    s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
02169 
02170    if (s) {
02171       cnf->recording = MEETME_RECORD_ACTIVE;
02172       while (ast_waitfor(cnf->chan, -1) > -1) {
02173          f = ast_read(cnf->chan);
02174          if (!f) {
02175             res = -1;
02176             break;
02177          }
02178          if (f->frametype == AST_FRAME_VOICE) {
02179             res = ast_writestream(s, f);
02180             if (res) {
02181                ast_frfree(f);
02182                break;
02183             }
02184          }
02185          ast_frfree(f);
02186          if (cnf->recording == MEETME_RECORD_TERMINATE) {
02187             ast_mutex_lock(&conflock);
02188             ast_mutex_unlock(&conflock);
02189             break;
02190          }
02191       }
02192       cnf->recording = MEETME_RECORD_OFF;
02193       ast_closestream(s);
02194    }
02195    pthread_exit(0);
02196 }

int reload void   ) 
 

Reload stuff.

This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.

Returns:
The return value is not used.

Definition at line 2254 of file app_meetme.c.

References load_config().

02255 {
02256    load_config();
02257 
02258    return 0;
02259 }

static void reset_volumes struct ast_conf_user user  )  [static]
 

Definition at line 395 of file app_meetme.c.

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

Referenced by conf_run().

00396 {
00397    signed char zero_volume = 0;
00398 
00399    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00400    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00401 }

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

Definition at line 324 of file app_meetme.c.

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

Referenced by tweak_listen_volume().

00325 {
00326    signed char gain_adjust;
00327 
00328    /* attempt to make the adjustment in the channel driver;
00329       if successful, don't adjust in the frame reading routine
00330    */
00331    gain_adjust = gain_map[volume + 5];
00332 
00333    return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00334 }

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

Definition at line 312 of file app_meetme.c.

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

Referenced by conf_run(), and tweak_talk_volume().

00313 {
00314    signed char gain_adjust;
00315 
00316    /* attempt to make the adjustment in the channel driver;
00317       if successful, don't adjust in the frame reading routine
00318    */
00319    gain_adjust = gain_map[volume + 5];
00320 
00321    return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00322 }

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

Definition at line 383 of file app_meetme.c.

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

Referenced by conf_run().

00384 {
00385    tweak_volume(&user->listen, action);
00386    /* attempt to make the adjustment in the channel driver;
00387       if successful, don't adjust in the frame reading routine
00388    */
00389    if (!set_listen_volume(user, user->listen.desired))
00390       user->listen.actual = 0;
00391    else
00392       user->listen.actual = user->listen.desired;
00393 }

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

Definition at line 371 of file app_meetme.c.

References set_talk_volume(), and tweak_volume().

Referenced by conf_run().

00372 {
00373    tweak_volume(&user->talk, action);
00374    /* attempt to make the adjustment in the channel driver;
00375       if successful, don't adjust in the frame reading routine
00376    */
00377    if (!set_talk_volume(user, user->talk.desired))
00378       user->talk.actual = 0;
00379    else
00380       user->talk.actual = user->talk.desired;
00381 }

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

Definition at line 336 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

00337 {
00338    switch (action) {
00339    case VOL_UP:
00340       switch (vol->desired) {
00341       case 5:
00342          break;
00343       case 0:
00344          vol->desired = 2;
00345          break;
00346       case -2:
00347          vol->desired = 0;
00348          break;
00349       default:
00350          vol->desired++;
00351          break;
00352       }
00353       break;
00354    case VOL_DOWN:
00355       switch (vol->desired) {
00356       case -5:
00357          break;
00358       case 2:
00359          vol->desired = 0;
00360          break;
00361       case 0:
00362          vol->desired = -2;
00363          break;
00364       default:
00365          vol->desired--;
00366          break;
00367       }
00368    }
00369 }

int unload_module void   ) 
 

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
Zero on success, or non-zero on error.

Definition at line 2224 of file app_meetme.c.

References app, app2, app3, ast_cli_unregister(), ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

02225 {
02226    int res;
02227    
02228    res = ast_cli_unregister(&cli_show_confs);
02229    res |= ast_cli_unregister(&cli_conf);
02230    res |= ast_unregister_application(app3);
02231    res |= ast_unregister_application(app2);
02232    res |= ast_unregister_application(app);
02233 
02234    STANDARD_HANGUP_LOCALUSERS;
02235 
02236    return res;
02237 }

int usecount void   ) 
 

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
The module's usecount.

Definition at line 2266 of file app_meetme.c.

References STANDARD_USECOUNT.

02267 {
02268    int res;
02269 
02270    STANDARD_USECOUNT(res);
02271 
02272    return res;
02273 }


Variable Documentation

const char* app = "MeetMe" [static]
 

Definition at line 60 of file app_meetme.c.

const char* app2 = "MeetMeCount" [static]
 

Definition at line 61 of file app_meetme.c.

const char* app3 = "MeetMeAdmin" [static]
 

Definition at line 62 of file app_meetme.c.

int audio_buffers [static]
 

Definition at line 174 of file app_meetme.c.

Referenced by conf_run(), and load_config().

struct ast_cli_entry cli_conf [static]
 

Initial value:

 {
   {"meetme", NULL, NULL }, conf_cmd,
   "Execute a command on a conference or conferee", conf_usage, complete_confcmd}

Definition at line 718 of file app_meetme.c.

struct ast_cli_entry cli_show_confs [static]
 

Initial value:

 {
   { "show", "conferences", NULL }, confs_show,
   "Show status of conferences", show_confs_usage, NULL }

Definition at line 513 of file app_meetme.c.

char conf_usage[] [static]
 

Initial value:

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

Definition at line 714 of file app_meetme.c.

struct ast_conference * confs [static]
 

Referenced by admin_exec(), build_conf(), complete_confcmd(), conf_cmd(), conf_exec(), conf_free(), and find_conf().

const char* descrip [static]
 

Definition at line 68 of file app_meetme.c.

const char* descrip2 [static]
 

Definition at line 105 of file app_meetme.c.

const char* descrip3 [static]
 

Definition at line 112 of file app_meetme.c.

signed char gain_map[] [static]
 

Definition at line 298 of file app_meetme.c.

LOCAL_USER_DECL
 

Definition at line 129 of file app_meetme.c.

char show_confs_usage[] [static]
 

Initial value:

"Deprecated! Please use 'meetme' instead.\n"

Definition at line 510 of file app_meetme.c.

STANDARD_LOCAL_USER
 

Definition at line 127 of file app_meetme.c.

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

Definition at line 64 of file app_meetme.c.

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

Definition at line 65 of file app_meetme.c.

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

Definition at line 66 of file app_meetme.c.

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

Definition at line 58 of file app_meetme.c.


Generated on Sun Aug 6 15:03:51 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2