Wed Oct 28 15:48:08 2009

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 "asterisk/linkedlists.h"
#include "enter.h"
#include "leave.h"

Include dependency graph for app_meetme.c:

Go to the source code of this file.

Data Structures

struct  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),})
static AST_LIST_HEAD_STATIC (confs, ast_conference)
static struct ast_conferencebuild_conf (char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount)
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 int dispose_conf (struct ast_conference *conf)
static struct ast_conferencefind_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, int refcount, 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 unsigned int conf_map [1024] = {0, }
static char conf_usage []
static const char * descrip
static const char * descrip2
static const char * descrip3
static signed char gain_map []
 LOCAL_USER_DECL
enum { ... }  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 186 of file app_meetme.c.

Referenced by admin_exec(), and conf_run().

#define ADMINFLAG_MUTED   (1 << 1)

Definition at line 185 of file app_meetme.c.

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

#define CONF_COMMANDS   6

Referenced by complete_confcmd().

#define CONF_SIZE   320

Definition at line 209 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_ADMIN   (1 << 1)

Definition at line 211 of file app_meetme.c.

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

#define CONFFLAG_AGI   (1 << 8)

Definition at line 218 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_ALWAYSPROMPT   (1 << 21)

Definition at line 231 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_ANNOUNCEUSERCOUNT   (1 << 7)

Definition at line 217 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_DYNAMIC   (1 << 17)

Definition at line 227 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_DYNAMICPIN   (1 << 18)

Definition at line 228 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_EMPTY   (1 << 19)

Definition at line 229 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_EMPTYNOPIN   (1 << 20)

Definition at line 230 of file app_meetme.c.

Referenced by conf_exec().

#define CONFFLAG_EXIT_CONTEXT   (1 << 12)

Definition at line 222 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_INTROUSER   (1 << 14)

Definition at line 224 of file app_meetme.c.

Referenced by conf_run(), and find_conf().

#define CONFFLAG_MARKEDEXIT   (1 << 10)

Definition at line 220 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_MARKEDUSER   (1 << 13)

Definition at line 223 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_MOH   (1 << 9)

Definition at line 219 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_MONITOR   (1 << 2)

Definition at line 212 of file app_meetme.c.

Referenced by conf_cmd(), and conf_run().

#define CONFFLAG_MONITORTALKER   (1 << 16)

Definition at line 226 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_POUNDEXIT   (1 << 3)

Definition at line 213 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_QUIET   (1 << 6)

Definition at line 216 of file app_meetme.c.

Referenced by conf_run(), and find_conf().

#define CONFFLAG_RECORDCONF   (1<< 15)

Definition at line 225 of file app_meetme.c.

Referenced by conf_run(), and find_conf().

#define CONFFLAG_STARMENU   (1 << 4)

Definition at line 214 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_TALKER   (1 << 5)

Definition at line 215 of file app_meetme.c.

Referenced by conf_run().

#define CONFFLAG_WAITMARKED   (1 << 11)

Definition at line 221 of file app_meetme.c.

Referenced by conf_run().

#define CONFIG_FILE_NAME   "meetme.conf"

Definition at line 127 of file app_meetme.c.

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

#define DEFAULT_AUDIO_BUFFERS   32

Definition at line 183 of file app_meetme.c.

Referenced by load_config().

#define ENTER   0

Definition at line 202 of file app_meetme.c.

Referenced by conf_play(), and conf_run().

#define LEAVE   1

Definition at line 203 of file app_meetme.c.

Referenced by conf_play(), and conf_run().

#define MEETME_DELAYDETECTENDTALK   1000

Definition at line 188 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_DELAYDETECTTALK   300

Definition at line 187 of file app_meetme.c.

Referenced by conf_run().

#define MEETME_RECORD_ACTIVE   1

Definition at line 206 of file app_meetme.c.

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

#define MEETME_RECORD_OFF   0

Definition at line 205 of file app_meetme.c.

Referenced by conf_free(), and recordthread().

#define MEETME_RECORD_TERMINATE   2

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

00233      {
00234    OPT_ARG_WAITMARKED = 0,
00235    OPT_ARG_ARRAY_SIZE = 1,
00236 } meetme_option_args;

Enumerator:
VOL_UP 
VOL_DOWN 

Definition at line 190 of file app_meetme.c.

00190                    {
00191    VOL_UP,
00192    VOL_DOWN,
00193 };


Function Documentation

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

Definition at line 2035 of file app_meetme.c.

References ADMINFLAG_KICKME, ADMINFLAG_MUTED, AST_LIST_LAST, AST_LIST_TRAVERSE, ast_log(), ast_strdupa, ast_strlen_zero(), CONFFLAG_ADMIN, dispose_conf(), find_conf(), find_user(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_NOTICE, LOG_WARNING, strsep(), and user.

Referenced by conf_cmd(), and load_module().

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

AST_APP_OPTIONS ( meetme_opts   ) 

static AST_LIST_HEAD_STATIC ( confs  ,
ast_conference   
) [static]

static struct ast_conference* build_conf ( char *  confno,
char *  pin,
char *  pinadmin,
int  make,
int  dynamic,
int  refcount 
) [static, read]

Definition at line 443 of file app_meetme.c.

References AST_FORMAT_ULAW, ast_hangup(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_request(), ast_verbose(), calloc, ast_conference::chan, conf_map, ast_conference::confno, ast_conference::fd, ast_channel::fds, free, LOG_WARNING, ast_conference::markedusers, option_verbose, VERBOSE_PREFIX_3, and ast_conference::zapconf.

Referenced by find_conf().

00444 {
00445    struct ast_conference *cnf;
00446    struct zt_confinfo ztc;
00447    int confno_int = 0;
00448 
00449    AST_LIST_LOCK(&confs);
00450    AST_LIST_TRAVERSE(&confs, cnf, list) {
00451       if (!strcmp(confno, cnf->confno)) 
00452          break;
00453    }
00454 
00455    if (!cnf && (make || dynamic)) {
00456       /* Make a new one */
00457       cnf = calloc(1, sizeof(*cnf));
00458       if (cnf) {
00459          ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00460          ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00461          ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00462          cnf->markedusers = 0;
00463          cnf->chan = ast_request("zap", AST_FORMAT_ULAW, "pseudo", NULL);
00464          if (cnf->chan) {
00465             cnf->fd = cnf->chan->fds[0];  /* for use by conf_play() */
00466          } else {
00467             ast_log(LOG_WARNING, "Unable to open pseudo channel - trying device\n");
00468             cnf->fd = open("/dev/zap/pseudo", O_RDWR);
00469             if (cnf->fd < 0) {
00470                ast_log(LOG_WARNING, "Unable to open pseudo device\n");
00471                free(cnf);
00472                cnf = NULL;
00473                goto cnfout;
00474             }
00475          }
00476          memset(&ztc, 0, sizeof(ztc));
00477          /* Setup a new zap conference */
00478          ztc.chan = 0;
00479          ztc.confno = -1;
00480          ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
00481          if (ioctl(cnf->fd, ZT_SETCONF, &ztc)) {
00482             ast_log(LOG_WARNING, "Error setting conference\n");
00483             if (cnf->chan)
00484                ast_hangup(cnf->chan);
00485             else
00486                close(cnf->fd);
00487             free(cnf);
00488             cnf = NULL;
00489             goto cnfout;
00490          }
00491          /* Fill the conference struct */
00492          cnf->start = time(NULL);
00493          cnf->zapconf = ztc.confno;
00494          cnf->isdynamic = dynamic;
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          AST_LIST_INSERT_HEAD(&confs, cnf, list);
00499          /* Reserve conference number in map */
00500          if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
00501             conf_map[confno_int] = 1;
00502       } else   
00503          ast_log(LOG_WARNING, "Out of memory\n");
00504    }
00505  cnfout:
00506    if (cnf)
00507       ast_atomic_fetchadd_int(&cnf->refcount, refcount);
00508    AST_LIST_UNLOCK(&confs);
00509    return cnf;
00510 }

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

Definition at line 272 of file app_meetme.c.

References ast_log(), and LOG_WARNING.

Referenced by conf_play(), and conf_run().

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

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

Definition at line 653 of file app_meetme.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strdupa, CONF_COMMANDS, ast_conference::confno, strdup, strsep(), and ast_conf_user::user_no.

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

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

Definition at line 526 of file app_meetme.c.

References admin_exec(), ADMINFLAG_MUTED, ast_cli(), AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), CONFFLAG_ADMIN, CONFFLAG_MONITOR, ast_conference::confno, istalking(), LOG_DEBUG, ast_conference::markedusers, RESULT_SHOWUSAGE, RESULT_SUCCESS, total, user, ast_conf_user::user_no, and ast_conference::users.

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

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

Definition at line 1778 of file app_meetme.c.

References ast_channel::_state, ast_answer(), ast_app_getdata(), ast_app_parse_options(), ast_config_destroy(), ast_config_load(), AST_DIGIT_ANY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_EXTENSION, ast_say_digits(), ast_set_flag, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_variable_browse(), ast_waitstream(), cfg, conf_map, conf_run(), CONFFLAG_ADMIN, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFIG_FILE_NAME, ast_conference::confno, dispose_conf(), find_conf(), ast_flags::flags, ast_channel::language, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, OPT_ARG_ARRAY_SIZE, strsep(), ast_variable::value, and var.

Referenced by load_module().

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

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

Definition at line 732 of file app_meetme.c.

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

Referenced by conf_run().

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

static int conf_free ( struct ast_conference conf  )  [static]

Definition at line 763 of file app_meetme.c.

References ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_conference::chan, ast_conference::fd, free, LOG_WARNING, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, and MEETME_RECORD_TERMINATE.

Referenced by dispose_conf().

00764 {
00765    struct ast_conference *cur;
00766 
00767    AST_LIST_TRAVERSE_SAFE_BEGIN(&confs, cur, list) {
00768       if (cur == conf) {
00769          AST_LIST_REMOVE_CURRENT(&confs, list);
00770          break;
00771       }
00772    }
00773    AST_LIST_TRAVERSE_SAFE_END;
00774 
00775    if (!cur)
00776       ast_log(LOG_WARNING, "Conference not found\n");
00777 
00778    if (conf->recording == MEETME_RECORD_ACTIVE) {
00779       conf->recording = MEETME_RECORD_TERMINATE;
00780       AST_LIST_UNLOCK(&confs);
00781       while (1) {
00782          usleep(1);
00783          AST_LIST_LOCK(&confs);
00784          if (conf->recording == MEETME_RECORD_OFF)
00785             break;
00786          AST_LIST_UNLOCK(&confs);
00787       }
00788    }
00789 
00790    if (conf->chan)
00791       ast_hangup(conf->chan);
00792    else
00793       close(conf->fd);
00794    
00795    free(conf);
00796 
00797    return 0;
00798 }

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

Definition at line 410 of file app_meetme.c.

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

Referenced by conf_run().

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

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

Definition at line 819 of file app_meetme.c.

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

Referenced by conf_exec().

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

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

Definition at line 512 of file app_meetme.c.

References ast_cli(), and RESULT_SUCCESS.

00513 {
00514    ast_cli(fd, "Deprecated! Please use 'meetme' instead.\n");
00515 
00516    return RESULT_SUCCESS;
00517 }

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

Definition at line 1731 of file app_meetme.c.

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

Referenced by load_module().

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

char* description ( void   ) 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 2234 of file app_meetme.c.

02235 {
02236    return (char *) tdesc;
02237 }

static int dispose_conf ( struct ast_conference conf  )  [static]

Definition at line 801 of file app_meetme.c.

References AST_LIST_LOCK, AST_LIST_UNLOCK, conf_free(), conf_map, and ast_conference::confno.

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

00802 {
00803    int res = 0;
00804    int confno_int = 0;
00805 
00806    AST_LIST_LOCK(&confs);
00807    if (ast_atomic_dec_and_test(&conf->refcount)) {
00808       /* Take the conference room number out of an inuse state */
00809       if ((sscanf(conf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
00810          conf_map[confno_int] = 0;
00811       conf_free(conf);
00812       res = 1;
00813    }
00814    AST_LIST_UNLOCK(&confs);
00815 
00816    return res;
00817 }

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

Definition at line 1634 of file app_meetme.c.

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

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

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

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

Definition at line 2014 of file app_meetme.c.

References AST_LIST_TRAVERSE, user, and ast_conf_user::user_no.

02015 {
02016    struct ast_conf_user *user = NULL;
02017    int cid;
02018 
02019    if (!conf || !callerident) {
02020       return NULL;
02021    }
02022 
02023    sscanf(callerident, "%30i", &cid);
02024 
02025    AST_LIST_TRAVERSE(&conf->userlist, user, list) {
02026       if (user->user_no == cid)
02027          break;
02028    }
02029 
02030    return user;
02031 }

static char* istalking ( int  x  )  [static]

Definition at line 262 of file app_meetme.c.

Referenced by conf_cmd().

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

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

References ASTERISK_GPL_KEY.

02249 {
02250    return ASTERISK_GPL_KEY;
02251 }

static void load_config ( void   )  [static]

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

02172 {
02173    struct ast_config *cfg;
02174    char *val;
02175 
02176    audio_buffers = DEFAULT_AUDIO_BUFFERS;
02177 
02178    if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
02179       return;
02180 
02181    if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
02182       if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
02183          ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
02184          audio_buffers = DEFAULT_AUDIO_BUFFERS;
02185       } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) {
02186          ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
02187             ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS);
02188          audio_buffers = DEFAULT_AUDIO_BUFFERS;
02189       }
02190       if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
02191          ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
02192    }
02193 
02194    ast_config_destroy(cfg);
02195 }

int load_module ( void   ) 

Initialize the module.

This function is called at module load time. Put all code in here that needs to set up your module's hardware, software, registrations, etc.

Returns:
This function should return 0 on success and non-zero on failure. If the module is not loaded successfully, Asterisk will call its unload_module() function.
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.
TE STUFF END

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

02213 {
02214    int res;
02215 
02216    load_config();
02217 
02218    res = ast_cli_register(&cli_show_confs);
02219    res |= ast_cli_register(&cli_conf);
02220    res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
02221    res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
02222    res |= ast_register_application(app, conf_exec, synopsis, descrip);
02223 
02224    return res;
02225 }

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

Definition at line 2130 of file app_meetme.c.

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

Referenced by conf_run().

02131 {
02132    struct ast_conference *cnf = args;
02133    struct ast_frame *f=NULL;
02134    int flags;
02135    struct ast_filestream *s;
02136    int res=0;
02137 
02138    if (!cnf || !cnf->chan) {
02139       pthread_exit(0);
02140    }
02141    ast_stopstream(cnf->chan);
02142    flags = O_CREAT|O_TRUNC|O_WRONLY;
02143    s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
02144 
02145    if (s) {
02146       cnf->recording = MEETME_RECORD_ACTIVE;
02147       while (ast_waitfor(cnf->chan, -1) > -1) {
02148          f = ast_read(cnf->chan);
02149          if (!f) {
02150             res = -1;
02151             break;
02152          }
02153          if (f->frametype == AST_FRAME_VOICE) {
02154             res = ast_writestream(s, f);
02155             if (res) {
02156                ast_frfree(f);
02157                break;
02158             }
02159          }
02160          ast_frfree(f);
02161          if (cnf->recording == MEETME_RECORD_TERMINATE) {
02162             break;
02163          }
02164       }
02165       cnf->recording = MEETME_RECORD_OFF;
02166       ast_closestream(s);
02167    }
02168    pthread_exit(0);
02169 }

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

References load_config().

02228 {
02229    load_config();
02230 
02231    return 0;
02232 }

static void reset_volumes ( struct ast_conf_user user  )  [static]

Definition at line 402 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_RXGAIN, and AST_OPTION_TXGAIN.

Referenced by conf_run().

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

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

Definition at line 331 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_TXGAIN, and gain_map.

Referenced by tweak_listen_volume().

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

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

Definition at line 319 of file app_meetme.c.

References ast_channel_setoption(), AST_OPTION_RXGAIN, and gain_map.

Referenced by conf_run(), and tweak_talk_volume().

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

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

Definition at line 390 of file app_meetme.c.

References set_listen_volume(), and tweak_volume().

Referenced by conf_run().

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

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

Definition at line 378 of file app_meetme.c.

References set_talk_volume(), and tweak_volume().

Referenced by conf_run().

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

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

Definition at line 343 of file app_meetme.c.

References volume::desired, VOL_DOWN, and VOL_UP.

Referenced by tweak_listen_volume(), and tweak_talk_volume().

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

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

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

02198 {
02199    int res;
02200    
02201    res = ast_cli_unregister(&cli_show_confs);
02202    res |= ast_cli_unregister(&cli_conf);
02203    res |= ast_unregister_application(app3);
02204    res |= ast_unregister_application(app2);
02205    res |= ast_unregister_application(app);
02206 
02207    STANDARD_HANGUP_LOCALUSERS;
02208 
02209    return res;
02210 }

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

References STANDARD_USECOUNT.

02240 {
02241    int res;
02242 
02243    STANDARD_USECOUNT(res);
02244 
02245    return res;
02246 }


Variable Documentation

const char* app = "MeetMe" [static]

Definition at line 61 of file app_meetme.c.

const char* app2 = "MeetMeCount" [static]

Definition at line 62 of file app_meetme.c.

const char* app3 = "MeetMeAdmin" [static]

Definition at line 63 of file app_meetme.c.

int audio_buffers [static]

Definition at line 179 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 728 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 522 of file app_meetme.c.

Referenced by load_module(), and unload_module().

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

Definition at line 157 of file app_meetme.c.

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

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

const char* descrip [static]

Definition at line 69 of file app_meetme.c.

const char* descrip2 [static]

Definition at line 107 of file app_meetme.c.

const char* descrip3 [static]

Definition at line 114 of file app_meetme.c.

signed char gain_map[] [static]

Definition at line 305 of file app_meetme.c.

Referenced by set_listen_volume(), and set_talk_volume().

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

Definition at line 129 of file app_meetme.c.

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

Definition at line 65 of file app_meetme.c.

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

Definition at line 66 of file app_meetme.c.

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

Definition at line 67 of file app_meetme.c.

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

Definition at line 59 of file app_meetme.c.


Generated on Wed Oct 28 15:48:08 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6