Sat Nov 25 00:45:45 2006

Asterisk developer's documentation


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"

Go to the source code of this file.

Data Structures

struct  ast_conf_user
struct  ast_conference
struct  volume

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  { OPT_ARG_WAITMARKED = 0, OPT_ARG_ARRAY_SIZE = 1 }
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_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_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, char *optargs[])
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
struct {
   int   alarm
   char *   description
   unsigned int   event_log:1
   enum queue_result   id
   char *   name
   char *   name
   char *   name
   rtpPayloadType   payloadType
   unsigned int   queue_log:1
   char *   subtype
   char *   text
   char *   type
   int   val
meetme_option_args
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 182 of file app_meetme.c.

Referenced by admin_exec().

#define ADMINFLAG_MUTED   (1 << 1)
 

Definition at line 181 of file app_meetme.c.

#define CONF_COMMANDS   6
 

Referenced by complete_confcmd().

#define CONF_SIZE   320
 

Definition at line 207 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_ADMIN   (1 << 1)
 

Definition at line 209 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_AGI   (1 << 8)
 

Definition at line 216 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_ALWAYSPROMPT   (1 << 21)
 

Definition at line 229 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_ANNOUNCEUSERCOUNT   (1 << 7)
 

Definition at line 215 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_DYNAMIC   (1 << 17)
 

Definition at line 225 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_DYNAMICPIN   (1 << 18)
 

Definition at line 226 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_EMPTY   (1 << 19)
 

Definition at line 227 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_EMPTYNOPIN   (1 << 20)
 

Definition at line 228 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_EXIT_CONTEXT   (1 << 12)
 

Definition at line 220 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_INTROUSER   (1 << 14)
 

Definition at line 222 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_MARKEDEXIT   (1 << 10)
 

Definition at line 218 of file app_meetme.c.

#define CONFFLAG_MARKEDUSER   (1 << 13)
 

Definition at line 221 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_MOH   (1 << 9)
 

Definition at line 217 of file app_meetme.c.

#define CONFFLAG_MONITOR   (1 << 2)
 

Definition at line 210 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_MONITORTALKER   (1 << 16)
 

Definition at line 224 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_POUNDEXIT   (1 << 3)
 

Definition at line 211 of file app_meetme.c.

#define CONFFLAG_QUIET   (1 << 6)
 

Definition at line 214 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_RECORDCONF   (1<< 15)
 

Definition at line 223 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_STARMENU   (1 << 4)
 

Definition at line 212 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_TALKER   (1 << 5)
 

Definition at line 213 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_WAITMARKED   (1 << 11)
 

Definition at line 219 of file app_meetme.c.

Referenced by conf_run().

#define CONFIG_FILE_NAME   "meetme.conf"
 

Definition at line 126 of file app_meetme.c.

Referenced by conf_exec(), and load_config().

#define DEFAULT_AUDIO_BUFFERS   32
 

Definition at line 179 of file app_meetme.c.

Referenced by load_config().

#define ENTER   0
 

Definition at line 200 of file app_meetme.c.

Referenced by conf_play(), and conf_run().

#define LEAVE   1
 

Definition at line 201 of file app_meetme.c.

Referenced by conf_play().

#define MEETME_DELAYDETECTENDTALK   1000
 

Definition at line 184 of file app_meetme.c.

#define MEETME_DELAYDETECTTALK   300
 

Definition at line 183 of file app_meetme.c.

#define MEETME_RECORD_ACTIVE   1
 

Definition at line 204 of file app_meetme.c.

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

#define MEETME_RECORD_OFF   0
 

Definition at line 203 of file app_meetme.c.

Referenced by conf_free(), and recordthread().

#define MEETME_RECORD_TERMINATE   2
 

Definition at line 205 of file app_meetme.c.

Referenced by conf_free(), and recordthread().


Enumeration Type Documentation

anonymous enum
 

Enumerator:
OPT_ARG_WAITMARKED 
OPT_ARG_ARRAY_SIZE 

Definition at line 231 of file app_meetme.c.

00231      {
00232    OPT_ARG_WAITMARKED = 0,
00233    OPT_ARG_ARRAY_SIZE = 1,
00234 } meetme_option_args;

enum volume_action
 

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 186 of file app_meetme.c.

00186                    {
00187    VOL_UP,
00188    VOL_DOWN,
00189 };


Function Documentation

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

Definition at line 2065 of file app_meetme.c.

References ADMINFLAG_KICKME, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), ast_conference::confno, confs, find_user(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, ast_conference::next, strsep(), and user.

Referenced by load_module().

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

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

References ast_mutex_lock(), ast_conference::confno, confs, and ast_conference::next.

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

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

Definition at line 270 of file app_meetme.c.

References ast_log(), and LOG_WARNING.

Referenced by conf_play(), and conf_run().

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

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

Definition at line 648 of file app_meetme.c.

References CONF_COMMANDS, and strdup.

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

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

Definition at line 522 of file app_meetme.c.

References ast_cli(), total, and user.

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

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

Definition at line 1787 of file app_meetme.c.

References ast_channel::_state, ast_answer(), ast_app_parse_options(), ast_config_destroy(), ast_config_load(), ast_log(), AST_MAX_EXTENSION, ast_mutex_lock(), ast_mutex_unlock(), AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_variable_browse(), cfg, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFIG_FILE_NAME, ast_conference::confno, confs, LOCAL_USER_ADD, LOG_ERROR, map, ast_conference::next, OPT_ARG_ARRAY_SIZE, strsep(), and var.

Referenced by load_module().

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

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

Definition at line 727 of file app_meetme.c.

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

Referenced by conf_run().

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

static int conf_free struct ast_conference conf  )  [static]
 

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

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

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

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

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

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

Definition at line 798 of file app_meetme.c.

References app, ast_channel_setoption(), ast_config_AST_SPOOL_DIR, AST_DIGIT_ANY, ast_dsp_new(), ast_fileexists(), AST_FORMAT_SLINEAR, AST_FRIENDLY_OFFSET, ast_indicate(), ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mutex_lock(), ast_mutex_unlock(), AST_OPTION_TONE_VERIFY, ast_pthread_create, 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_waitstream(), ast_conference::attr, calloc, ast_conference::chan, ast_conf_user::chan, conf_flush(), conf_play(), CONF_SIZE, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROUSER, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, 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_channel::language, ast_conference::lastuser, ast_conference::locked, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, manager_event(), ast_conference::markedusers, MEETME_RECORD_ACTIVE, ast_channel::name, ast_conf_user::nextuser, OPT_ARG_WAITMARKED, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, recordthread(), ast_conference::recordthread, set_talk_volume(), ast_channel::type, ast_channel::uniqueid, user, ast_conf_user::user_no, ast_conference::users, VERBOSE_PREFIX_4, and ast_conference::zapconf.

Referenced by conf_exec().

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

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

Definition at line 508 of file app_meetme.c.

References ast_cli(), and RESULT_SUCCESS.

00509 {
00510    ast_cli(fd, "Deprecated! Please use 'meetme' instead.\n");
00511 
00512    return RESULT_SUCCESS;
00513 }

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

Definition at line 1742 of file app_meetme.c.

References ast_channel::_state, ast_answer(), ast_log(), ast_say_number(), AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_conference::chan, 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().

01743 {
01744    struct localuser *u;
01745    int res = 0;
01746    struct ast_conference *conf;
01747    int count;
01748    char *confnum, *localdata;
01749    char val[80] = "0"; 
01750 
01751    if (ast_strlen_zero(data)) {
01752       ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
01753       return -1;
01754    }
01755 
01756    LOCAL_USER_ADD(u);
01757    
01758    localdata = ast_strdupa(data);
01759    if (!localdata) {
01760       ast_log(LOG_ERROR, "Out of memory!\n");
01761       LOCAL_USER_REMOVE(u);
01762       return -1;
01763    }
01764    
01765    confnum = strsep(&localdata,"|");       
01766    conf = find_conf(chan, confnum, 0, 0, NULL, NULL);
01767    if (conf)
01768       count = conf->users;
01769    else
01770       count = 0;
01771 
01772    if (!ast_strlen_zero(localdata)){
01773       /* have var so load it and exit */
01774       snprintf(val, sizeof(val), "%d",count);
01775       pbx_builtin_setvar_helper(chan, localdata, val);
01776    } else {
01777       if (chan->_state != AST_STATE_UP)
01778          ast_answer(chan);
01779       res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
01780    }
01781    LOCAL_USER_REMOVE(u);
01782 
01783    return res;
01784 }

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 2286 of file app_meetme.c.

02287 {
02288    return (char *) tdesc;
02289 }

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

References ast_mutex_lock(), cfg, ast_conference::confno, confs, ast_conference::next, and var.

Referenced by count_exec().

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

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

Definition at line 2042 of file app_meetme.c.

References ast_conference::firstuser, and user.

02043 {
02044    struct ast_conf_user *user = NULL;
02045    int cid;
02046 
02047    if (!conf || !callerident) {
02048       return NULL;
02049    }
02050 
02051    sscanf(callerident, "%i", &cid);
02052 
02053    user = conf->firstuser;
02054    while (user) {
02055       if (user->user_no == cid)
02056          break;
02057       user = user->nextuser;
02058    }
02059 
02060    return user;
02061 }

static char* istalking int  x  )  [static]
 

Definition at line 260 of file app_meetme.c.

00261 {
00262    if (x > 0)
00263       return "(talking)";
00264    else if (x < 0)
00265       return "(unmonitored)";
00266    else 
00267       return "(not talking)";
00268 }

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

References ASTERISK_GPL_KEY.

02301 {
02302    return ASTERISK_GPL_KEY;
02303 }

static void load_config void   )  [static]
 

Definition at line 2223 of file app_meetme.c.

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

02224 {
02225    struct ast_config *cfg;
02226    char *val;
02227 
02228    audio_buffers = DEFAULT_AUDIO_BUFFERS;
02229 
02230    if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
02231       return;
02232 
02233    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
02234       if ((sscanf(val, "%d", &audio_buffers) != 1)) {
02235          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
02236          audio_buffers = DEFAULT_AUDIO_BUFFERS;
02237       } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) {
02238          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
02239             ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS);
02240          audio_buffers = DEFAULT_AUDIO_BUFFERS;
02241       }
02242       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
02243          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
02244    }
02245 
02246    ast_config_destroy(cfg);
02247 }

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

References admin_exec(), ast_cli_register(), ast_register_application(), cli_conf, cli_show_confs, conf_exec(), count_exec(), and load_config().

02265 {
02266    int res;
02267 
02268    load_config();
02269 
02270    res = ast_cli_register(&cli_show_confs);
02271    res |= ast_cli_register(&cli_conf);
02272    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
02273    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
02274    res |= ast_register_application(app, conf_exec, synopsis, descrip);
02275 
02276    return res;
02277 }

static void * recordthread void *  args  )  [static]
 

Definition at line 2180 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_filestream::f, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, and s.

Referenced by conf_run().

02181 {
02182    struct ast_conference *cnf = args;
02183    struct ast_frame *f=NULL;
02184    int flags;
02185    struct ast_filestream *s;
02186    int res=0;
02187 
02188    if (!cnf || !cnf->chan) {
02189       pthread_exit(0);
02190    }
02191    ast_stopstream(cnf->chan);
02192    flags = O_CREAT|O_TRUNC|O_WRONLY;
02193    s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
02194 
02195    if (s) {
02196       cnf->recording = MEETME_RECORD_ACTIVE;
02197       while (ast_waitfor(cnf->chan, -1) > -1) {
02198          f = ast_read(cnf->chan);
02199          if (!f) {
02200             res = -1;
02201             break;
02202          }
02203          if (f->frametype == AST_FRAME_VOICE) {
02204             res = ast_writestream(s, f);
02205             if (res) {
02206                ast_frfree(f);
02207                break;
02208             }
02209          }
02210          ast_frfree(f);
02211          if (cnf->recording == MEETME_RECORD_TERMINATE) {
02212             ast_mutex_lock(&conflock);
02213             ast_mutex_unlock(&conflock);
02214             break;
02215          }
02216       }
02217       cnf->recording = MEETME_RECORD_OFF;
02218       ast_closestream(s);
02219    }
02220    pthread_exit(0);
02221 }

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

References load_config().

02280 {
02281    load_config();
02282 
02283    return 0;
02284 }

static void reset_volumes struct ast_conf_user user  )  [static]
 

Definition at line 400 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_RXGAIN, AST_OPTION_TXGAIN, and user.

00401 {
00402    signed char zero_volume = 0;
00403 
00404    ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00405    ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00406 }

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

Definition at line 329 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_TXGAIN, and user.

Referenced by tweak_listen_volume().

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

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

Definition at line 317 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_RXGAIN, and user.

Referenced by conf_run(), and tweak_talk_volume().

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

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

Definition at line 388 of file app_meetme.c.

References set_listen_volume(), tweak_volume(), and user.

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

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

Definition at line 376 of file app_meetme.c.

References set_talk_volume(), tweak_volume(), and user.

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

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

Definition at line 341 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

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

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

References ast_cli_unregister(), ast_unregister_application(), cli_conf, cli_show_confs, and STANDARD_HANGUP_LOCALUSERS.

02250 {
02251    int res;
02252    
02253    res = ast_cli_unregister(&cli_show_confs);
02254    res |= ast_cli_unregister(&cli_conf);
02255    res |= ast_unregister_application(app3);
02256    res |= ast_unregister_application(app2);
02257    res |= ast_unregister_application(app);
02258 
02259    STANDARD_HANGUP_LOCALUSERS;
02260 
02261    return res;
02262 }

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

References STANDARD_USECOUNT.

02292 {
02293    int res;
02294 
02295    STANDARD_USECOUNT(res);
02296 
02297    return res;
02298 }


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

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

Referenced by load_module(), and unload_module().

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

Referenced by load_module(), and unload_module().

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

struct ast_conference * confs [static]
 

Referenced by admin_exec(), build_conf(), 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 106 of file app_meetme.c.

const char* descrip3 [static]
 

Definition at line 113 of file app_meetme.c.

signed char gain_map[] [static]
 

Definition at line 303 of file app_meetme.c.

LOCAL_USER_DECL
 

Definition at line 130 of file app_meetme.c.

enum { ... } meetme_option_args
 

char show_confs_usage[] [static]
 

Initial value:

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

Definition at line 515 of file app_meetme.c.

STANDARD_LOCAL_USER
 

Definition at line 128 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 Sat Nov 25 00:45:45 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6