#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <zaptel.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/options.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "enter.h"
#include "leave.h"
Go to the source code of this file.
Data Structures | |
struct | ast_conf_user |
struct | ast_conference |
struct | volume |
Defines | |
#define | ADMINFLAG_KICKME (1 << 2) |
#define | ADMINFLAG_MUTED (1 << 1) |
#define | CONF_COMMANDS 6 |
#define | CONF_SIZE 320 |
#define | CONFFLAG_ADMIN (1 << 1) |
#define | CONFFLAG_AGI (1 << 8) |
#define | CONFFLAG_ALWAYSPROMPT (1 << 21) |
#define | CONFFLAG_ANNOUNCEUSERCOUNT (1 << 7) |
#define | CONFFLAG_DYNAMIC (1 << 17) |
#define | CONFFLAG_DYNAMICPIN (1 << 18) |
#define | CONFFLAG_EMPTY (1 << 19) |
#define | CONFFLAG_EMPTYNOPIN (1 << 20) |
#define | CONFFLAG_EXIT_CONTEXT (1 << 12) |
#define | CONFFLAG_INTROUSER (1 << 14) |
#define | CONFFLAG_MARKEDEXIT (1 << 10) |
#define | CONFFLAG_MARKEDUSER (1 << 13) |
#define | CONFFLAG_MOH (1 << 9) |
#define | CONFFLAG_MONITOR (1 << 2) |
#define | CONFFLAG_MONITORTALKER (1 << 16) |
#define | CONFFLAG_POUNDEXIT (1 << 3) |
#define | CONFFLAG_QUIET (1 << 6) |
#define | CONFFLAG_RECORDCONF (1<< 15) |
#define | CONFFLAG_STARMENU (1 << 4) |
#define | CONFFLAG_TALKER (1 << 5) |
#define | CONFFLAG_WAITMARKED (1 << 11) |
#define | CONFIG_FILE_NAME "meetme.conf" |
#define | DEFAULT_AUDIO_BUFFERS 32 |
#define | ENTER 0 |
#define | LEAVE 1 |
#define | MEETME_DELAYDETECTENDTALK 1000 |
#define | MEETME_DELAYDETECTTALK 300 |
#define | MEETME_RECORD_ACTIVE 1 |
#define | MEETME_RECORD_OFF 0 |
#define | MEETME_RECORD_TERMINATE 2 |
Enumerations | |
enum | { OPT_ARG_WAITMARKED = 0, OPT_ARG_ARRAY_SIZE = 1 } |
enum | volume_action { VOL_UP, VOL_DOWN } |
Functions | |
static int | admin_exec (struct ast_channel *chan, void *data) |
AST_APP_OPTIONS (meetme_opts,{AST_APP_OPTION('a', CONFFLAG_ADMIN), AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT), AST_APP_OPTION('T', CONFFLAG_MONITORTALKER), AST_APP_OPTION('i', CONFFLAG_INTROUSER), AST_APP_OPTION('m', CONFFLAG_MONITOR), AST_APP_OPTION('p', CONFFLAG_POUNDEXIT), AST_APP_OPTION('s', CONFFLAG_STARMENU), AST_APP_OPTION('t', CONFFLAG_TALKER), AST_APP_OPTION('q', CONFFLAG_QUIET), AST_APP_OPTION('M', CONFFLAG_MOH), AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT), AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT), AST_APP_OPTION('A', CONFFLAG_MARKEDUSER), AST_APP_OPTION('b', CONFFLAG_AGI), AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED), AST_APP_OPTION('r', CONFFLAG_RECORDCONF), AST_APP_OPTION('d', CONFFLAG_DYNAMIC), AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN), AST_APP_OPTION('e', CONFFLAG_EMPTY), AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN), AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT),}) | |
AST_MUTEX_DEFINE_STATIC (conflock) | |
static struct ast_conference * | build_conf (char *confno, char *pin, char *pinadmin, int make, int dynamic) |
static int | careful_write (int fd, unsigned char *data, int len, int block) |
static char * | complete_confcmd (char *line, char *word, int pos, int state) |
static int | conf_cmd (int fd, int argc, char **argv) |
static int | conf_exec (struct ast_channel *chan, void *data) |
static void | conf_flush (int fd, struct ast_channel *chan) |
static int | conf_free (struct ast_conference *conf) |
static void | conf_play (struct ast_channel *chan, struct ast_conference *conf, int sound) |
static int | conf_run (struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[]) |
static int | confs_show (int fd, int argc, char **argv) |
static int | count_exec (struct ast_channel *chan, void *data) |
char * | description (void) |
Provides a description of the module. | |
static struct ast_conference * | find_conf (struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, struct ast_flags *confflags) |
static struct ast_conf_user * | find_user (struct ast_conference *conf, char *callerident) |
static char * | istalking (int x) |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
static void | load_config (void) |
int | load_module (void) |
Initialize the module. | |
static void * | recordthread (void *args) |
int | reload (void) |
Reload stuff. | |
static void | reset_volumes (struct ast_conf_user *user) |
static int | set_listen_volume (struct ast_conf_user *user, int volume) |
static int | set_talk_volume (struct ast_conf_user *user, int volume) |
static void | tweak_listen_volume (struct ast_conf_user *user, enum volume_action action) |
static void | tweak_talk_volume (struct ast_conf_user *user, enum volume_action action) |
static void | tweak_volume (struct volume *vol, enum volume_action action) |
int | unload_module (void) |
Cleanup all module structures, sockets, etc. | |
int | usecount (void) |
Provides a usecount. | |
Variables | |
static const char * | app = "MeetMe" |
static const char * | app2 = "MeetMeCount" |
static const char * | app3 = "MeetMeAdmin" |
static int | audio_buffers |
static struct ast_cli_entry | cli_conf |
static struct ast_cli_entry | cli_show_confs |
static char | conf_usage [] |
static struct ast_conference * | confs |
static const char * | descrip |
static const char * | descrip2 |
static const char * | descrip3 |
static signed char | gain_map [] |
LOCAL_USER_DECL | |
struct { | |
int alarm | |
char * description | |
unsigned int event_log:1 | |
enum queue_result id | |
char * name | |
char * name | |
char * name | |
rtpPayloadType payloadType | |
unsigned int queue_log:1 | |
char * subtype | |
char * text | |
char * type | |
int val | |
} | meetme_option_args |
static char | show_confs_usage [] |
STANDARD_LOCAL_USER | |
static const char * | synopsis = "MeetMe conference bridge" |
static const char * | synopsis2 = "MeetMe participant count" |
static const char * | synopsis3 = "MeetMe conference Administration" |
static const char * | tdesc = "MeetMe conference bridge" |
Definition in file app_meetme.c.
|
Definition at line 182 of file app_meetme.c. Referenced by admin_exec(). |
|
Definition at line 181 of file app_meetme.c. |
|
Referenced by complete_confcmd(). |
|
Definition at line 207 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 209 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 216 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 229 of file app_meetme.c. Referenced by conf_exec(). |
|
Definition at line 215 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 225 of file app_meetme.c. Referenced by conf_exec(). |
|
Definition at line 226 of file app_meetme.c. Referenced by conf_exec(). |
|
Definition at line 227 of file app_meetme.c. Referenced by conf_exec(). |
|
Definition at line 228 of file app_meetme.c. Referenced by conf_exec(). |
|
Definition at line 220 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 222 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 218 of file app_meetme.c. |
|
Definition at line 221 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 217 of file app_meetme.c. |
|
Definition at line 210 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 224 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 211 of file app_meetme.c. |
|
Definition at line 214 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 223 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 212 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 213 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 219 of file app_meetme.c. Referenced by conf_run(). |
|
Definition at line 126 of file app_meetme.c. Referenced by conf_exec(), and load_config(). |
|
Definition at line 179 of file app_meetme.c. Referenced by load_config(). |
|
Definition at line 200 of file app_meetme.c. Referenced by conf_play(), and conf_run(). |
|
Definition at line 201 of file app_meetme.c. Referenced by conf_play(). |
|
Definition at line 184 of file app_meetme.c. |
|
Definition at line 183 of file app_meetme.c. |
|
Definition at line 204 of file app_meetme.c. Referenced by conf_free(), conf_run(), and recordthread(). |
|
Definition at line 203 of file app_meetme.c. Referenced by conf_free(), and recordthread(). |
|
Definition at line 205 of file app_meetme.c. Referenced by conf_free(), and recordthread(). |
|
Definition at line 231 of file app_meetme.c. 00231 { 00232 OPT_ARG_WAITMARKED = 0, 00233 OPT_ARG_ARRAY_SIZE = 1, 00234 } meetme_option_args;
|
|
Definition at line 186 of file app_meetme.c.
|
|
Definition at line 2065 of file app_meetme.c. References ADMINFLAG_KICKME, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), ast_conference::confno, confs, find_user(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_WARNING, ast_conference::next, strsep(), and user. Referenced by load_module(). 02065 { 02066 char *params, *command = NULL, *caller = NULL, *conf = NULL; 02067 struct ast_conference *cnf; 02068 struct ast_conf_user *user = NULL; 02069 struct localuser *u; 02070 02071 LOCAL_USER_ADD(u); 02072 02073 ast_mutex_lock(&conflock); 02074 /* The param has the conference number the user and the command to execute */ 02075 if (!ast_strlen_zero(data)) { 02076 params = ast_strdupa((char *) data); 02077 conf = strsep(¶ms, "|"); 02078 command = strsep(¶ms, "|"); 02079 caller = strsep(¶ms, "|"); 02080 02081 if (!command) { 02082 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n"); 02083 ast_mutex_unlock(&conflock); 02084 LOCAL_USER_REMOVE(u); 02085 return -1; 02086 } 02087 for (cnf = confs; cnf; cnf = cnf->next) { 02088 if (!strcmp(cnf->confno, conf)) 02089 break; 02090 } 02091 02092 if (caller) 02093 user = find_user(cnf, caller); 02094 02095 if (cnf) { 02096 switch((int) (*command)) { 02097 case 76: /* L: Lock */ 02098 cnf->locked = 1; 02099 break; 02100 case 108: /* l: Unlock */ 02101 cnf->locked = 0; 02102 break; 02103 case 75: /* K: kick all users*/ 02104 user = cnf->firstuser; 02105 while(user) { 02106 user->adminflags |= ADMINFLAG_KICKME; 02107 if (user->nextuser) { 02108 user = user->nextuser; 02109 } else { 02110 break; 02111 } 02112 } 02113 break; 02114 case 101: /* e: Eject last user*/ 02115 user = cnf->lastuser; 02116 if (!(user->userflags & CONFFLAG_ADMIN)) { 02117 user->adminflags |= ADMINFLAG_KICKME; 02118 break; 02119 } else 02120 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n"); 02121 break; 02122 case 77: /* M: Mute */ 02123 if (user) { 02124 user->adminflags |= ADMINFLAG_MUTED; 02125 } else { 02126 ast_log(LOG_NOTICE, "Specified User not found!\n"); 02127 } 02128 break; 02129 case 78: /* N: Mute all users */ 02130 user = cnf->firstuser; 02131 while(user) { 02132 if (user && !(user->userflags & CONFFLAG_ADMIN)) 02133 user->adminflags |= ADMINFLAG_MUTED; 02134 if (user->nextuser) { 02135 user = user->nextuser; 02136 } else { 02137 break; 02138 } 02139 } 02140 break; 02141 case 109: /* m: Unmute */ 02142 if (user && (user->adminflags & ADMINFLAG_MUTED)) { 02143 user->adminflags ^= ADMINFLAG_MUTED; 02144 } else { 02145 ast_log(LOG_NOTICE, "Specified User not found or he muted himself!\n"); 02146 } 02147 break; 02148 case 110: /* n: Unmute all users */ 02149 user = cnf->firstuser; 02150 while(user) { 02151 if (user && (user-> adminflags & ADMINFLAG_MUTED)) { 02152 user->adminflags ^= ADMINFLAG_MUTED; 02153 } 02154 if (user->nextuser) { 02155 user = user->nextuser; 02156 } else { 02157 break; 02158 } 02159 } 02160 break; 02161 case 107: /* k: Kick user */ 02162 if (user) { 02163 user->adminflags |= ADMINFLAG_KICKME; 02164 } else { 02165 ast_log(LOG_NOTICE, "Specified User not found!\n"); 02166 } 02167 break; 02168 } 02169 } else { 02170 ast_log(LOG_NOTICE, "Conference Number not found\n"); 02171 } 02172 } 02173 ast_mutex_unlock(&conflock); 02174 02175 LOCAL_USER_REMOVE(u); 02176 02177 return 0; 02178 }
|
|
|
|
|
|
Definition at line 441 of file app_meetme.c. References ast_mutex_lock(), ast_conference::confno, confs, and ast_conference::next. 00442 { 00443 struct ast_conference *cnf; 00444 struct zt_confinfo ztc; 00445 00446 ast_mutex_lock(&conflock); 00447 00448 for (cnf = confs; cnf; cnf = cnf->next) { 00449 if (!strcmp(confno, cnf->confno)) 00450 break; 00451 } 00452 00453 if (!cnf && (make || dynamic)) { 00454 /* Make a new one */ 00455 cnf = calloc(1, sizeof(*cnf)); 00456 if (cnf) { 00457 ast_copy_string(cnf->confno, confno, sizeof(cnf->confno)); 00458 ast_copy_string(cnf->pin, pin, sizeof(cnf->pin)); 00459 ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin)); 00460 cnf->markedusers = 0; 00461 cnf->chan = ast_request("zap", AST_FORMAT_ULAW, "pseudo", NULL); 00462 if (cnf->chan) { 00463 cnf->fd = cnf->chan->fds[0]; /* for use by conf_play() */ 00464 } else { 00465 ast_log(LOG_WARNING, "Unable to open pseudo channel - trying device\n"); 00466 cnf->fd = open("/dev/zap/pseudo", O_RDWR); 00467 if (cnf->fd < 0) { 00468 ast_log(LOG_WARNING, "Unable to open pseudo device\n"); 00469 free(cnf); 00470 cnf = NULL; 00471 goto cnfout; 00472 } 00473 } 00474 memset(&ztc, 0, sizeof(ztc)); 00475 /* Setup a new zap conference */ 00476 ztc.chan = 0; 00477 ztc.confno = -1; 00478 ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON; 00479 if (ioctl(cnf->fd, ZT_SETCONF, &ztc)) { 00480 ast_log(LOG_WARNING, "Error setting conference\n"); 00481 if (cnf->chan) 00482 ast_hangup(cnf->chan); 00483 else 00484 close(cnf->fd); 00485 free(cnf); 00486 cnf = NULL; 00487 goto cnfout; 00488 } 00489 /* Fill the conference struct */ 00490 cnf->start = time(NULL); 00491 cnf->zapconf = ztc.confno; 00492 cnf->isdynamic = dynamic; 00493 cnf->firstuser = NULL; 00494 cnf->lastuser = NULL; 00495 cnf->locked = 0; 00496 if (option_verbose > 2) 00497 ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno); 00498 cnf->next = confs; 00499 confs = cnf; 00500 } else 00501 ast_log(LOG_WARNING, "Out of memory\n"); 00502 } 00503 cnfout: 00504 ast_mutex_unlock(&conflock); 00505 return cnf; 00506 }
|
|
Definition at line 270 of file app_meetme.c. References ast_log(), and LOG_WARNING. Referenced by conf_play(), and conf_run(). 00271 { 00272 int res; 00273 int x; 00274 00275 while (len) { 00276 if (block) { 00277 x = ZT_IOMUX_WRITE | ZT_IOMUX_SIGEVENT; 00278 res = ioctl(fd, ZT_IOMUX, &x); 00279 } else 00280 res = 0; 00281 if (res >= 0) 00282 res = write(fd, data, len); 00283 if (res < 1) { 00284 if (errno != EAGAIN) { 00285 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno)); 00286 return -1; 00287 } else 00288 return 0; 00289 } 00290 len -= res; 00291 data += res; 00292 } 00293 00294 return 0; 00295 }
|
|
Definition at line 648 of file app_meetme.c. References CONF_COMMANDS, and strdup. 00648 { 00649 #define CONF_COMMANDS 6 00650 int which = 0, x = 0; 00651 struct ast_conference *cnf = NULL; 00652 struct ast_conf_user *usr = NULL; 00653 char *confno = NULL; 00654 char usrno[50] = ""; 00655 char cmds[CONF_COMMANDS][20] = {"lock", "unlock", "mute", "unmute", "kick", "list"}; 00656 char *myline; 00657 00658 if (pos == 1) { 00659 /* Command */ 00660 for (x = 0;x < CONF_COMMANDS; x++) { 00661 if (!strncasecmp(cmds[x], word, strlen(word))) { 00662 if (++which > state) { 00663 return strdup(cmds[x]); 00664 } 00665 } 00666 } 00667 } else if (pos == 2) { 00668 /* Conference Number */ 00669 ast_mutex_lock(&conflock); 00670 cnf = confs; 00671 while(cnf) { 00672 if (!strncasecmp(word, cnf->confno, strlen(word))) { 00673 if (++which > state) 00674 break; 00675 } 00676 cnf = cnf->next; 00677 } 00678 ast_mutex_unlock(&conflock); 00679 return cnf ? strdup(cnf->confno) : NULL; 00680 } else if (pos == 3) { 00681 /* User Number || Conf Command option*/ 00682 if (strstr(line, "mute") || strstr(line, "kick")) { 00683 if ((state == 0) && (strstr(line, "kick") || strstr(line,"mute")) && !(strncasecmp(word, "all", strlen(word)))) { 00684 return strdup("all"); 00685 } 00686 which++; 00687 ast_mutex_lock(&conflock); 00688 00689 /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */ 00690 myline = ast_strdupa(line); 00691 if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) { 00692 while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0)) 00693 ; 00694 } 00695 00696 for (cnf = confs; cnf; cnf = cnf->next) { 00697 if (!strcmp(confno, cnf->confno)) 00698 break; 00699 } 00700 00701 if (cnf) { 00702 /* Search for the user */ 00703 for (usr = cnf->firstuser; usr; usr = usr->nextuser) { 00704 snprintf(usrno, sizeof(usrno), "%d", usr->user_no); 00705 if (!strncasecmp(word, usrno, strlen(word))) { 00706 if (++which > state) 00707 break; 00708 } 00709 } 00710 } 00711 ast_mutex_unlock(&conflock); 00712 return usr ? strdup(usrno) : NULL; 00713 } 00714 } 00715 00716 return NULL; 00717 }
|
|
Definition at line 522 of file app_meetme.c. References ast_cli(), total, and user. 00522 { 00523 /* Process the command */ 00524 struct ast_conference *cnf; 00525 struct ast_conf_user *user; 00526 int hr, min, sec; 00527 int i = 0, total = 0; 00528 time_t now; 00529 char *header_format = "%-14s %-14s %-10s %-8s %-8s\n"; 00530 char *data_format = "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s\n"; 00531 char cmdline[1024] = ""; 00532 00533 if (argc > 8) 00534 ast_cli(fd, "Invalid Arguments.\n"); 00535 /* Check for length so no buffer will overflow... */ 00536 for (i = 0; i < argc; i++) { 00537 if (strlen(argv[i]) > 100) 00538 ast_cli(fd, "Invalid Arguments.\n"); 00539 } 00540 if (argc == 1) { 00541 /* 'MeetMe': List all the conferences */ 00542 now = time(NULL); 00543 cnf = confs; 00544 if (!cnf) { 00545 ast_cli(fd, "No active MeetMe conferences.\n"); 00546 return RESULT_SUCCESS; 00547 } 00548 ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation"); 00549 while(cnf) { 00550 if (cnf->markedusers == 0) 00551 strcpy(cmdline, "N/A "); 00552 else 00553 snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers); 00554 hr = (now - cnf->start) / 3600; 00555 min = ((now - cnf->start) % 3600) / 60; 00556 sec = (now - cnf->start) % 60; 00557 00558 ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static"); 00559 00560 total += cnf->users; 00561 cnf = cnf->next; 00562 } 00563 ast_cli(fd, "* Total number of MeetMe users: %d\n", total); 00564 return RESULT_SUCCESS; 00565 } 00566 if (argc < 3) 00567 return RESULT_SHOWUSAGE; 00568 ast_copy_string(cmdline, argv[2], sizeof(cmdline)); /* Argv 2: conference number */ 00569 if (strstr(argv[1], "lock")) { 00570 if (strcmp(argv[1], "lock") == 0) { 00571 /* Lock */ 00572 strncat(cmdline, "|L", sizeof(cmdline) - strlen(cmdline) - 1); 00573 } else { 00574 /* Unlock */ 00575 strncat(cmdline, "|l", sizeof(cmdline) - strlen(cmdline) - 1); 00576 } 00577 } else if (strstr(argv[1], "mute")) { 00578 if (argc < 4) 00579 return RESULT_SHOWUSAGE; 00580 if (strcmp(argv[1], "mute") == 0) { 00581 /* Mute */ 00582 if (strcmp(argv[3], "all") == 0) { 00583 strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1); 00584 } else { 00585 strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1); 00586 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1); 00587 } 00588 } else { 00589 /* Unmute */ 00590 if (strcmp(argv[3], "all") == 0) { 00591 strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1); 00592 } else { 00593 strncat(cmdline, "|m|", sizeof(cmdline) - strlen(cmdline) - 1); 00594 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1); 00595 } 00596 } 00597 } else if (strcmp(argv[1], "kick") == 0) { 00598 if (argc < 4) 00599 return RESULT_SHOWUSAGE; 00600 if (strcmp(argv[3], "all") == 0) { 00601 /* Kick all */ 00602 strncat(cmdline, "|K", sizeof(cmdline) - strlen(cmdline) - 1); 00603 } else { 00604 /* Kick a single user */ 00605 strncat(cmdline, "|k|", sizeof(cmdline) - strlen(cmdline) - 1); 00606 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1); 00607 } 00608 } else if(strcmp(argv[1], "list") == 0) { 00609 /* List all the users in a conference */ 00610 if (!confs) { 00611 ast_cli(fd, "No active conferences.\n"); 00612 return RESULT_SUCCESS; 00613 } 00614 cnf = confs; 00615 /* Find the right conference */ 00616 while(cnf) { 00617 if (strcmp(cnf->confno, argv[2]) == 0) 00618 break; 00619 if (cnf->next) { 00620 cnf = cnf->next; 00621 } else { 00622 ast_cli(fd, "No such conference: %s.\n",argv[2]); 00623 return RESULT_SUCCESS; 00624 } 00625 } 00626 /* Show all the users */ 00627 for (user = cnf->firstuser; user; user = user->nextuser) 00628 ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s\n", 00629 user->user_no, 00630 user->chan->cid.cid_num ? user->chan->cid.cid_num : "<unknown>", 00631 user->chan->cid.cid_name ? user->chan->cid.cid_name : "<no name>", 00632 user->chan->name, 00633 user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "", 00634 user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "", 00635 user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : "", 00636 istalking(user->talking)); 00637 ast_cli(fd,"%d users in that conference.\n",cnf->users); 00638 00639 return RESULT_SUCCESS; 00640 } else 00641 return RESULT_SHOWUSAGE; 00642 ast_log(LOG_DEBUG, "Cmdline: %s\n", cmdline); 00643 admin_exec(NULL, cmdline); 00644 00645 return 0; 00646 }
|
|
Definition at line 1787 of file app_meetme.c. References ast_channel::_state, ast_answer(), ast_app_parse_options(), ast_config_destroy(), ast_config_load(), ast_log(), AST_MAX_EXTENSION, ast_mutex_lock(), ast_mutex_unlock(), AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_variable_browse(), cfg, CONFFLAG_ALWAYSPROMPT, CONFFLAG_DYNAMIC, CONFFLAG_DYNAMICPIN, CONFFLAG_EMPTY, CONFFLAG_EMPTYNOPIN, CONFIG_FILE_NAME, ast_conference::confno, confs, LOCAL_USER_ADD, LOG_ERROR, map, ast_conference::next, OPT_ARG_ARRAY_SIZE, strsep(), and var. Referenced by load_module(). 01788 { 01789 int res=-1; 01790 struct localuser *u; 01791 char confno[AST_MAX_EXTENSION] = ""; 01792 int allowretry = 0; 01793 int retrycnt = 0; 01794 struct ast_conference *cnf; 01795 struct ast_flags confflags = {0}; 01796 int dynamic = 0; 01797 int empty = 0, empty_no_pin = 0; 01798 int always_prompt = 0; 01799 char *notdata, *info, *inflags = NULL, *inpin = NULL, the_pin[AST_MAX_EXTENSION] = ""; 01800 char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, }; 01801 01802 LOCAL_USER_ADD(u); 01803 01804 if (ast_strlen_zero(data)) { 01805 allowretry = 1; 01806 notdata = ""; 01807 } else { 01808 notdata = data; 01809 } 01810 01811 if (chan->_state != AST_STATE_UP) 01812 ast_answer(chan); 01813 01814 info = ast_strdupa(notdata); 01815 01816 if (info) { 01817 char *tmp = strsep(&info, "|"); 01818 ast_copy_string(confno, tmp, sizeof(confno)); 01819 if (ast_strlen_zero(confno)) { 01820 allowretry = 1; 01821 } 01822 } 01823 if (info) 01824 inflags = strsep(&info, "|"); 01825 if (info) 01826 inpin = strsep(&info, "|"); 01827 if (inpin) 01828 ast_copy_string(the_pin, inpin, sizeof(the_pin)); 01829 01830 if (inflags) { 01831 ast_app_parse_options(meetme_opts, &confflags, optargs, inflags); 01832 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN); 01833 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !inpin) 01834 strcpy(the_pin, "q"); 01835 01836 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN); 01837 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN); 01838 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT); 01839 } 01840 01841 do { 01842 if (retrycnt > 3) 01843 allowretry = 0; 01844 if (empty) { 01845 int i, map[1024] = { 0, }; 01846 struct ast_config *cfg; 01847 struct ast_variable *var; 01848 int confno_int; 01849 01850 ast_mutex_lock(&conflock); 01851 for (cnf = confs; cnf; cnf = cnf->next) { 01852 if (sscanf(cnf->confno, "%d", &confno_int) == 1) { 01853 /* Disqualify in use conference */ 01854 if (confno_int >= 0 && confno_int < 1024) 01855 map[confno_int]++; 01856 } 01857 } 01858 ast_mutex_unlock(&conflock); 01859 01860 /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */ 01861 if ((empty_no_pin) || (!dynamic)) { 01862 cfg = ast_config_load(CONFIG_FILE_NAME); 01863 if (cfg) { 01864 var = ast_variable_browse(cfg, "rooms"); 01865 while (var) { 01866 if (!strcasecmp(var->name, "conf")) { 01867 char *stringp = ast_strdupa(var->value); 01868 if (stringp) { 01869 char *confno_tmp = strsep(&stringp, "|,"); 01870 int found = 0; 01871 if (sscanf(confno_tmp, "%d", &confno_int) == 1) { 01872 if ((confno_int >= 0) && (confno_int < 1024)) { 01873 if (stringp && empty_no_pin) { 01874 map[confno_int]++; 01875 } 01876 } 01877 } 01878 if (!dynamic) { 01879 /* For static: run through the list and see if this conference is empty */ 01880 ast_mutex_lock(&conflock); 01881 cnf = confs; 01882 while (cnf) { 01883 if (!strcmp(confno_tmp, cnf->confno)) { 01884 /* The conference exists, therefore it's not empty */ 01885 found = 1; 01886 break; 01887 } 01888 cnf = cnf->next; 01889 } 01890 ast_mutex_unlock(&conflock); 01891 if (!found) { 01892 /* At this point, we have a confno_tmp (static conference) that is empty */ 01893 if ((empty_no_pin && ((!stringp) || (stringp && (stringp[0] == '\0')))) || (!empty_no_pin)) { 01894 /* Case 1: empty_no_pin and pin is nonexistent (NULL) 01895 * Case 2: empty_no_pin and pin is blank (but not NULL) 01896 * Case 3: not empty_no_pin 01897 */ 01898 ast_copy_string(confno, confno_tmp, sizeof(confno)); 01899 break; 01900 /* XXX the map is not complete (but we do have a confno) */ 01901 } 01902 } 01903 } 01904 } else { 01905 ast_log(LOG_ERROR, "Out of memory\n"); 01906 } 01907 } 01908 var = var->next; 01909 } 01910 ast_config_destroy(cfg); 01911 } 01912 } 01913 01914 /* Select first conference number not in use */ 01915 if (ast_strlen_zero(confno) && dynamic) { 01916 for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) { 01917 if (!map[i]) { 01918 snprintf(confno, sizeof(confno), "%d", i); 01919 break; 01920 } 01921 } 01922 } 01923 01924 /* Not found? */ 01925 if (ast_strlen_zero(confno)) { 01926 res = ast_streamfile(chan, "conf-noempty", chan->language); 01927 if (!res) 01928 ast_waitstream(chan, ""); 01929 } else { 01930 if (sscanf(confno, "%d", &confno_int) == 1) { 01931 res = ast_streamfile(chan, "conf-enteringno", chan->language); 01932 if (!res) { 01933 ast_waitstream(chan, ""); 01934 res = ast_say_digits(chan, confno_int, "", chan->language); 01935 } 01936 } else { 01937 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno); 01938 } 01939 } 01940 } 01941 01942 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) { 01943 /* Prompt user for conference number */ 01944 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0); 01945 if (res < 0) { 01946 /* Don't try to validate when we catch an error */ 01947 confno[0] = '\0'; 01948 allowretry = 0; 01949 break; 01950 } 01951 } 01952 if (!ast_strlen_zero(confno)) { 01953 /* Check the validity of the conference */ 01954 cnf = find_conf(chan, confno, 1, dynamic, the_pin, &confflags); 01955 if (!cnf) { 01956 res = ast_streamfile(chan, "conf-invalid", chan->language); 01957 if (!res) 01958 ast_waitstream(chan, ""); 01959 res = -1; 01960 if (allowretry) 01961 confno[0] = '\0'; 01962 } else { 01963 if ((!ast_strlen_zero(cnf->pin) && 01964 !ast_test_flag(&confflags, CONFFLAG_ADMIN)) || 01965 (!ast_strlen_zero(cnf->pinadmin) && 01966 ast_test_flag(&confflags, CONFFLAG_ADMIN))) { 01967 char pin[AST_MAX_EXTENSION]=""; 01968 int j; 01969 01970 /* Allow the pin to be retried up to 3 times */ 01971 for (j = 0; j < 3; j++) { 01972 if (*the_pin && (always_prompt == 0)) { 01973 ast_copy_string(pin, the_pin, sizeof(pin)); 01974 res = 0; 01975 } else { 01976 /* Prompt user for pin if pin is required */ 01977 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0); 01978 } 01979 if (res >= 0) { 01980 if (!strcasecmp(pin, cnf->pin) || 01981 (!ast_strlen_zero(cnf->pinadmin) && 01982 !strcasecmp(pin, cnf->pinadmin))) { 01983 /* Pin correct */ 01984 allowretry = 0; 01985 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 01986 ast_set_flag(&confflags, CONFFLAG_ADMIN); 01987 /* Run the conference */ 01988 res = conf_run(chan, cnf, confflags.flags, optargs); 01989 break; 01990 } else { 01991 /* Pin invalid */ 01992 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) { 01993 res = ast_waitstream(chan, AST_DIGIT_ANY); 01994 ast_stopstream(chan); 01995 } 01996 else { 01997 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n"); 01998 break; 01999 } 02000 if (res < 0) 02001 break; 02002 pin[0] = res; 02003 pin[1] = '\0'; 02004 res = -1; 02005 if (allowretry) 02006 confno[0] = '\0'; 02007 } 02008 } else { 02009 /* failed when getting the pin */ 02010 res = -1; 02011 allowretry = 0; 02012 /* see if we need to get rid of the conference */ 02013 ast_mutex_lock(&conflock); 02014 if (!cnf->users) { 02015 conf_free(cnf); 02016 } 02017 ast_mutex_unlock(&conflock); 02018 break; 02019 } 02020 02021 /* Don't retry pin with a static pin */ 02022 if (*the_pin && (always_prompt==0)) { 02023 break; 02024 } 02025 } 02026 } else { 02027 /* No pin required */ 02028 allowretry = 0; 02029 02030 /* Run the conference */ 02031 res = conf_run(chan, cnf, confflags.flags, optargs); 02032 } 02033 } 02034 } 02035 } while (allowretry); 02036 02037 LOCAL_USER_REMOVE(u); 02038 02039 return res; 02040 }
|
|
Definition at line 727 of file app_meetme.c. References ast_frfree(), ast_log(), ast_read(), ast_waitfor(), and LOG_WARNING. Referenced by conf_run(). 00728 { 00729 int x; 00730 00731 /* read any frames that may be waiting on the channel 00732 and throw them away 00733 */ 00734 if (chan) { 00735 struct ast_frame *f; 00736 00737 /* when no frames are available, this will wait 00738 for 1 millisecond maximum 00739 */ 00740 while (ast_waitfor(chan, 1)) { 00741 f = ast_read(chan); 00742 if (f) 00743 ast_frfree(f); 00744 else /* channel was hung up or something else happened */ 00745 break; 00746 } 00747 } 00748 00749 /* flush any data sitting in the pseudo channel */ 00750 x = ZT_FLUSH_ALL; 00751 if (ioctl(fd, ZT_FLUSH, &x)) 00752 ast_log(LOG_WARNING, "Error flushing channel\n"); 00753 00754 }
|
|
Definition at line 758 of file app_meetme.c. References ast_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_conference::chan, confs, ast_conference::fd, free, LOG_WARNING, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, ast_conference::next, and ast_conference::recording. 00759 { 00760 struct ast_conference *prev = NULL, *cur = confs; 00761 00762 while (cur) { 00763 if (cur == conf) { 00764 if (prev) 00765 prev->next = conf->next; 00766 else 00767 confs = conf->next; 00768 break; 00769 } 00770 prev = cur; 00771 cur = cur->next; 00772 } 00773 00774 if (!cur) 00775 ast_log(LOG_WARNING, "Conference not found\n"); 00776 00777 if (conf->recording == MEETME_RECORD_ACTIVE) { 00778 conf->recording = MEETME_RECORD_TERMINATE; 00779 ast_mutex_unlock(&conflock); 00780 while (1) { 00781 ast_mutex_lock(&conflock); 00782 if (conf->recording == MEETME_RECORD_OFF) 00783 break; 00784 ast_mutex_unlock(&conflock); 00785 } 00786 } 00787 00788 if (conf->chan) 00789 ast_hangup(conf->chan); 00790 else 00791 close(conf->fd); 00792 00793 free(conf); 00794 00795 return 0; 00796 }
|
|
Definition at line 408 of file app_meetme.c. References ast_channel::_softhangup, ast_autoservice_start(), ast_autoservice_stop(), ast_mutex_lock(), ast_mutex_unlock(), careful_write(), enter, ENTER, ast_conference::fd, leave, and LEAVE. Referenced by conf_run(). 00409 { 00410 unsigned char *data; 00411 int len; 00412 int res = -1; 00413 00414 if (!chan->_softhangup) 00415 res = ast_autoservice_start(chan); 00416 00417 ast_mutex_lock(&conflock); 00418 00419 switch(sound) { 00420 case ENTER: 00421 data = enter; 00422 len = sizeof(enter); 00423 break; 00424 case LEAVE: 00425 data = leave; 00426 len = sizeof(leave); 00427 break; 00428 default: 00429 data = NULL; 00430 len = 0; 00431 } 00432 if (data) 00433 careful_write(conf->fd, data, len, 1); 00434 00435 ast_mutex_unlock(&conflock); 00436 00437 if (!res) 00438 ast_autoservice_stop(chan); 00439 }
|
|
Definition at line 798 of file app_meetme.c. References app, ast_channel_setoption(), ast_config_AST_SPOOL_DIR, AST_DIGIT_ANY, ast_dsp_new(), ast_fileexists(), AST_FORMAT_SLINEAR, AST_FRIENDLY_OFFSET, ast_indicate(), ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_mutex_lock(), ast_mutex_unlock(), AST_OPTION_TONE_VERIFY, ast_pthread_create, ast_record_review(), ast_say_number(), ast_set_read_format(), ast_set_write_format(), ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), ast_conference::attr, calloc, ast_conference::chan, ast_conf_user::chan, conf_flush(), conf_play(), CONF_SIZE, CONFFLAG_ADMIN, CONFFLAG_AGI, CONFFLAG_ANNOUNCEUSERCOUNT, CONFFLAG_EXIT_CONTEXT, CONFFLAG_INTROUSER, CONFFLAG_MARKEDUSER, CONFFLAG_MONITOR, CONFFLAG_MONITORTALKER, CONFFLAG_QUIET, CONFFLAG_RECORDCONF, CONFFLAG_STARMENU, CONFFLAG_TALKER, CONFFLAG_WAITMARKED, ast_conference::confno, ast_channel::context, dsp, ENTER, EVENT_FLAG_CALL, exitcontext, ast_channel::fds, ast_conference::firstuser, ast_channel::language, ast_conference::lastuser, ast_conference::locked, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_channel::macrocontext, manager_event(), ast_conference::markedusers, MEETME_RECORD_ACTIVE, ast_channel::name, ast_conf_user::nextuser, OPT_ARG_WAITMARKED, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, recordthread(), ast_conference::recordthread, set_talk_volume(), ast_channel::type, ast_channel::uniqueid, user, ast_conf_user::user_no, ast_conference::users, VERBOSE_PREFIX_4, and ast_conference::zapconf. Referenced by conf_exec(). 00799 { 00800 struct ast_conf_user *user = calloc(1, sizeof(*user)); 00801 struct ast_conf_user *usr = NULL; 00802 int fd; 00803 struct zt_confinfo ztc, ztc_empty; 00804 struct ast_frame *f; 00805 struct ast_channel *c; 00806 struct ast_frame fr; 00807 int outfd; 00808 int ms; 00809 int nfds; 00810 int res; 00811 int flags; 00812 int retryzap; 00813 int origfd; 00814 int musiconhold = 0; 00815 int firstpass = 0; 00816 int lastmarked = 0; 00817 int currentmarked = 0; 00818 int ret = -1; 00819 int x; 00820 int menu_active = 0; 00821 int using_pseudo = 0; 00822 int duration=20; 00823 struct ast_dsp *dsp=NULL; 00824 struct ast_app *app; 00825 char *agifile; 00826 char *agifiledefault = "conf-background.agi"; 00827 char meetmesecs[30] = ""; 00828 char exitcontext[AST_MAX_CONTEXT] = ""; 00829 char recordingtmp[AST_MAX_EXTENSION] = ""; 00830 int dtmf, opt_waitmarked_timeout = 0; 00831 time_t timeout = 0; 00832 ZT_BUFFERINFO bi; 00833 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; 00834 char *buf = __buf + AST_FRIENDLY_OFFSET; 00835 00836 if (!user) { 00837 ast_log(LOG_ERROR, "Out of memory\n"); 00838 return ret; 00839 } 00840 00841 /* Possible timeout waiting for marked user */ 00842 if ((confflags & CONFFLAG_WAITMARKED) && 00843 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) && 00844 (sscanf(optargs[OPT_ARG_WAITMARKED], "%d", &opt_waitmarked_timeout) == 1) && 00845 (opt_waitmarked_timeout > 0)) { 00846 timeout = time(NULL) + opt_waitmarked_timeout; 00847 } 00848 00849 if (confflags & CONFFLAG_RECORDCONF && conf->recording !=MEETME_RECORD_ACTIVE) { 00850 conf->recordingfilename = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"); 00851 if (!conf->recordingfilename) { 00852 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid); 00853 conf->recordingfilename = ast_strdupa(recordingtmp); 00854 } 00855 conf->recordingformat = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"); 00856 if (!conf->recordingformat) { 00857 snprintf(recordingtmp, sizeof(recordingtmp), "wav"); 00858 conf->recordingformat = ast_strdupa(recordingtmp); 00859 } 00860 pthread_attr_init(&conf->attr); 00861 pthread_attr_setdetachstate(&conf->attr, PTHREAD_CREATE_DETACHED); 00862 ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n", 00863 conf->confno, conf->recordingfilename, conf->recordingformat); 00864 ast_pthread_create(&conf->recordthread, &conf->attr, recordthread, conf); 00865 } 00866 00867 time(&user->jointime); 00868 00869 if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) { 00870 /* Sorry, but this confernce is locked! */ 00871 if (!ast_streamfile(chan, "conf-locked", chan->language)) 00872 ast_waitstream(chan, ""); 00873 goto outrun; 00874 } 00875 00876 if (confflags & CONFFLAG_MARKEDUSER) 00877 conf->markedusers++; 00878 00879 ast_mutex_lock(&conflock); 00880 if (!conf->firstuser) { 00881 /* Fill the first new User struct */ 00882 user->user_no = 1; 00883 conf->firstuser = user; 00884 conf->lastuser = user; 00885 } else { 00886 /* Fill the new user struct */ 00887 user->user_no = conf->lastuser->user_no + 1; 00888 user->prevuser = conf->lastuser; 00889 if (conf->lastuser->nextuser) { 00890 ast_log(LOG_WARNING, "Error in User Management!\n"); 00891 ast_mutex_unlock(&conflock); 00892 goto outrun; 00893 } else { 00894 conf->lastuser->nextuser = user; 00895 conf->lastuser = user; 00896 } 00897 } 00898 00899 user->chan = chan; 00900 user->userflags = confflags; 00901 user->adminflags = 0; 00902 user->talking = -1; 00903 conf->users++; 00904 ast_mutex_unlock(&conflock); 00905 00906 if (confflags & CONFFLAG_EXIT_CONTEXT) { 00907 if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) 00908 ast_copy_string(exitcontext, agifile, sizeof(exitcontext)); 00909 else if (!ast_strlen_zero(chan->macrocontext)) 00910 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); 00911 else 00912 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); 00913 } 00914 00915 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER)) { 00916 snprintf(user->namerecloc, sizeof(user->namerecloc), 00917 "%s/meetme/meetme-username-%s-%d", ast_config_AST_SPOOL_DIR, 00918 conf->confno, user->user_no); 00919 res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL); 00920 if (res == -1) 00921 goto outrun; 00922 } 00923 00924 if (!(confflags & CONFFLAG_QUIET)) { 00925 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED)) 00926 if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) 00927 ast_waitstream(chan, ""); 00928 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0) 00929 if (!ast_streamfile(chan, "conf-waitforleader", chan->language)) 00930 ast_waitstream(chan, ""); 00931 } 00932 00933 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) { 00934 int keepplaying = 1; 00935 00936 if (conf->users == 2) { 00937 if (!ast_streamfile(chan,"conf-onlyone",chan->language)) { 00938 res = ast_waitstream(chan, AST_DIGIT_ANY); 00939 ast_stopstream(chan); 00940 if (res > 0) 00941 keepplaying=0; 00942 else if (res == -1) 00943 goto outrun; 00944 } 00945 } else { 00946 if (!ast_streamfile(chan, "conf-thereare", chan->language)) { 00947 res = ast_waitstream(chan, AST_DIGIT_ANY); 00948 ast_stopstream(chan); 00949 if (res > 0) 00950 keepplaying=0; 00951 else if (res == -1) 00952 goto outrun; 00953 } 00954 if (keepplaying) { 00955 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL); 00956 if (res > 0) 00957 keepplaying=0; 00958 else if (res == -1) 00959 goto outrun; 00960 } 00961 if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) { 00962 res = ast_waitstream(chan, AST_DIGIT_ANY); 00963 ast_stopstream(chan); 00964 if (res > 0) 00965 keepplaying=0; 00966 else if (res == -1) 00967 goto outrun; 00968 } 00969 } 00970 } 00971 00972 ast_indicate(chan, -1); 00973 00974 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00975 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name); 00976 goto outrun; 00977 } 00978 00979 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) { 00980 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name); 00981 goto outrun; 00982 } 00983 00984 retryzap = strcasecmp(chan->type, "Zap"); 00985 user->zapchannel = !retryzap; 00986 00987 zapretry: 00988 origfd = chan->fds[0]; 00989 if (retryzap) { 00990 fd = open("/dev/zap/pseudo", O_RDWR); 00991 if (fd < 0) { 00992 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); 00993 goto outrun; 00994 } 00995 using_pseudo = 1; 00996 /* Make non-blocking */ 00997 flags = fcntl(fd, F_GETFL); 00998 if (flags < 0) { 00999 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno)); 01000 close(fd); 01001 goto outrun; 01002 } 01003 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { 01004 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno)); 01005 close(fd); 01006 goto outrun; 01007 } 01008 /* Setup buffering information */ 01009 memset(&bi, 0, sizeof(bi)); 01010 bi.bufsize = CONF_SIZE/2; 01011 bi.txbufpolicy = ZT_POLICY_IMMEDIATE; 01012 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; 01013 bi.numbufs = audio_buffers; 01014 if (ioctl(fd, ZT_SET_BUFINFO, &bi)) { 01015 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); 01016 close(fd); 01017 goto outrun; 01018 } 01019 x = 1; 01020 if (ioctl(fd, ZT_SETLINEAR, &x)) { 01021 ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno)); 01022 close(fd); 01023 goto outrun; 01024 } 01025 nfds = 1; 01026 } else { 01027 /* XXX Make sure we're not running on a pseudo channel XXX */ 01028 fd = chan->fds[0]; 01029 nfds = 0; 01030 } 01031 memset(&ztc, 0, sizeof(ztc)); 01032 memset(&ztc_empty, 0, sizeof(ztc_empty)); 01033 /* Check to see if we're in a conference... */ 01034 ztc.chan = 0; 01035 if (ioctl(fd, ZT_GETCONF, &ztc)) { 01036 ast_log(LOG_WARNING, "Error getting conference\n"); 01037 close(fd); 01038 goto outrun; 01039 } 01040 if (ztc.confmode) { 01041 /* Whoa, already in a conference... Retry... */ 01042 if (!retryzap) { 01043 ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n"); 01044 retryzap = 1; 01045 goto zapretry; 01046 } 01047 } 01048 memset(&ztc, 0, sizeof(ztc)); 01049 /* Add us to the conference */ 01050 ztc.chan = 0; 01051 ztc.confno = conf->zapconf; 01052 01053 ast_mutex_lock(&conflock); 01054 01055 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER) && conf->users > 1) { 01056 if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) { 01057 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language)) 01058 ast_waitstream(conf->chan, ""); 01059 if (!ast_streamfile(conf->chan, "conf-hasjoin", chan->language)) 01060 ast_waitstream(conf->chan, ""); 01061 } 01062 } 01063 01064 if (confflags & CONFFLAG_MONITOR) 01065 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER; 01066 else if (confflags & CONFFLAG_TALKER) 01067 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; 01068 else 01069 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; 01070 01071 if (ioctl(fd, ZT_SETCONF, &ztc)) { 01072 ast_log(LOG_WARNING, "Error setting conference\n"); 01073 close(fd); 01074 ast_mutex_unlock(&conflock); 01075 goto outrun; 01076 } 01077 ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf); 01078 01079 manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 01080 "Channel: %s\r\n" 01081 "Uniqueid: %s\r\n" 01082 "Meetme: %s\r\n" 01083 "Usernum: %d\r\n", 01084 chan->name, chan->uniqueid, conf->confno, user->user_no); 01085 01086 if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { 01087 firstpass = 1; 01088 if (!(confflags & CONFFLAG_QUIET)) 01089 if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1))) 01090 conf_play(chan, conf, ENTER); 01091 } 01092 01093 ast_mutex_unlock(&conflock); 01094 01095 conf_flush(fd, chan); 01096 01097 if (confflags & CONFFLAG_AGI) { 01098 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND) 01099 or use default filename of conf-background.agi */ 01100 01101 agifile = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"); 01102 if (!agifile) 01103 agifile = agifiledefault; 01104 01105 if (user->zapchannel) { 01106 /* Set CONFMUTE mode on Zap channel to mute DTMF tones */ 01107 x = 1; 01108 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0); 01109 } 01110 /* Find a pointer to the agi app and execute the script */ 01111 app = pbx_findapp("agi"); 01112 if (app) { 01113 ret = pbx_exec(chan, app, agifile, 1); 01114 } else { 01115 ast_log(LOG_WARNING, "Could not find application (agi)\n"); 01116 ret = -2; 01117 } 01118 if (user->zapchannel) { 01119 /* Remove CONFMUTE mode on Zap channel */ 01120 x = 0; 01121 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0); 01122 } 01123 } else { 01124 if (user->zapchannel && (confflags & CONFFLAG_STARMENU)) { 01125 /* Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */ 01126 x = 1; 01127 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0); 01128 } 01129 if (confflags & CONFFLAG_MONITORTALKER && !(dsp = ast_dsp_new())) { 01130 ast_log(LOG_WARNING, "Unable to allocate DSP!\n"); 01131 res = -1; 01132 } 01133 for(;;) { 01134 int menu_was_active = 0; 01135 01136 outfd = -1; 01137 ms = -1; 01138 01139 if (timeout && time(NULL) >= timeout) 01140 break; 01141 01142 /* if we have just exited from the menu, and the user had a channel-driver 01143 volume adjustment, restore it 01144 */ 01145 if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual) 01146 set_talk_volume(user, user->listen.desired); 01147 01148 menu_was_active = menu_active; 01149 01150 currentmarked = conf->markedusers; 01151 if (!(confflags & CONFFLAG_QUIET) && 01152 (confflags & CONFFLAG_MARKEDUSER) && 01153 (confflags & CONFFLAG_WAITMARKED) && 01154 lastmarked == 0) { 01155 if (currentmarked == 1 && conf->users > 1) { 01156 ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL); 01157 if (conf->users - 1 == 1) { 01158 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language)) 01159 ast_waitstream(chan, ""); 01160 } else { 01161 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language)) 01162 ast_waitstream(chan, ""); 01163 } 01164 } 01165 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER)) 01166 if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) 01167 ast_waitstream(chan, ""); 01168 } 01169 01170 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); 01171 01172 /* Update the struct with the actual confflags */ 01173 user->userflags = confflags; 01174 01175 if (confflags & CONFFLAG_WAITMARKED) { 01176 if(currentmarked == 0) { 01177 if (lastmarked != 0) { 01178 if (!(confflags & CONFFLAG_QUIET)) 01179 if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language)) 01180 ast_waitstream(chan, ""); 01181 if(confflags & CONFFLAG_MARKEDEXIT) 01182 break; 01183 else { 01184 ztc.confmode = ZT_CONF_CONF; 01185 if (ioctl(fd, ZT_SETCONF, &ztc)) { 01186 ast_log(LOG_WARNING, "Error setting conference\n"); 01187 close(fd); 01188 goto outrun; 01189 } 01190 } 01191 } 01192 if (musiconhold == 0 && (confflags & CONFFLAG_MOH)) { 01193 ast_moh_start(chan, NULL); 01194 musiconhold = 1; 01195 } else { 01196 ztc.confmode = ZT_CONF_CONF; 01197 if (ioctl(fd, ZT_SETCONF, &ztc)) { 01198 ast_log(LOG_WARNING, "Error setting conference\n"); 01199 close(fd); 01200 goto outrun; 01201 } 01202 } 01203 } else if(currentmarked >= 1 && lastmarked == 0) { 01204 /* Marked user entered, so cancel timeout */ 01205 timeout = 0; 01206 if (confflags & CONFFLAG_MONITOR) 01207 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER; 01208 else if (confflags & CONFFLAG_TALKER) 01209 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; 01210 else 01211 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; 01212 if (ioctl(fd, ZT_SETCONF, &ztc)) { 01213 ast_log(LOG_WARNING, "Error setting conference\n"); 01214 close(fd); 01215 goto outrun; 01216 } 01217 if (musiconhold && (confflags & CONFFLAG_MOH)) { 01218 ast_moh_stop(chan); 01219 musiconhold = 0; 01220 } 01221 if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) { 01222 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language)) 01223 ast_waitstream(chan, ""); 01224 conf_play(chan, conf, ENTER); 01225 } 01226 } 01227 } 01228 01229 /* trying to add moh for single person conf */ 01230 if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) { 01231 if (conf->users == 1) { 01232 if (musiconhold == 0) { 01233 ast_moh_start(chan, NULL); 01234 musiconhold = 1; 01235 } 01236 } else { 01237 if (musiconhold) { 01238 ast_moh_stop(chan); 01239 musiconhold = 0; 01240 } 01241 } 01242 } 01243 01244 /* Leave if the last marked user left */ 01245 if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) { 01246 ret = -1; 01247 break; 01248 } 01249 01250 /* Check if the admin changed my modes */ 01251 if (user->adminflags) { 01252 /* Set the new modes */ 01253 if ((user->adminflags & ADMINFLAG_MUTED) && (ztc.confmode & ZT_CONF_TALKER)) { 01254 ztc.confmode ^= ZT_CONF_TALKER; 01255 if (ioctl(fd, ZT_SETCONF, &ztc)) { 01256 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); 01257 ret = -1; 01258 break; 01259 } 01260 } 01261 if (!(user->adminflags & ADMINFLAG_MUTED) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) { 01262 ztc.confmode |= ZT_CONF_TALKER; 01263 if (ioctl(fd, ZT_SETCONF, &ztc)) { 01264 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); 01265 ret = -1; 01266 break; 01267 } 01268 } 01269 if (user->adminflags & ADMINFLAG_KICKME) { 01270 /* You have been kicked. */ 01271 if (!ast_streamfile(chan, "conf-kicked", chan->language)) 01272 ast_waitstream(chan, ""); 01273 ret = 0; 01274 break; 01275 } 01276 } else if (!(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) { 01277 ztc.confmode |= ZT_CONF_TALKER; 01278 if (ioctl(fd, ZT_SETCONF, &ztc)) { 01279 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); 01280 ret = -1; 01281 break; 01282 } 01283 } 01284 01285 if (c) { 01286 if (c->fds[0] != origfd) { 01287 if (using_pseudo) { 01288 /* Kill old pseudo */ 01289 close(fd); 01290 using_pseudo = 0; 01291 } 01292 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n"); 01293 retryzap = strcasecmp(c->type, "Zap"); 01294 user->zapchannel = !retryzap; 01295 goto zapretry; 01296 } 01297 f = ast_read(c); 01298 if (!f) 01299 break; 01300 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) { 01301 if (user->talk.actual) 01302 ast_frame_adjust_volume(f, user->talk.actual); 01303 01304 if (confflags & CONFFLAG_MONITORTALKER) { 01305 int totalsilence; 01306 01307 if (user->talking == -1) 01308 user->talking = 0; 01309 01310 res = ast_dsp_silence(dsp, f, &totalsilence); 01311 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) { 01312 user->talking = 1; 01313 manager_event(EVENT_FLAG_CALL, "MeetmeTalking", 01314 "Channel: %s\r\n" 01315 "Uniqueid: %s\r\n" 01316 "Meetme: %s\r\n" 01317 "Usernum: %d\r\n", 01318 chan->name, chan->uniqueid, conf->confno, user->user_no); 01319 } 01320 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) { 01321 user->talking = 0; 01322 manager_event(EVENT_FLAG_CALL, "MeetmeStopTalking", 01323 "Channel: %s\r\n" 01324 "Uniqueid: %s\r\n" 01325 "Meetme: %s\r\n" 01326 "Usernum: %d\r\n", 01327 chan->name, chan->uniqueid, conf->confno, user->user_no); 01328 } 01329 } 01330 if (using_pseudo) { 01331 /* Absolutely do _not_ use careful_write here... 01332 it is important that we read data from the channel 01333 as fast as it arrives, and feed it into the conference. 01334 The buffering in the pseudo channel will take care of any 01335 timing differences, unless they are so drastic as to lose 01336 audio frames (in which case carefully writing would only 01337 have delayed the audio even further). 01338 */ 01339 /* As it turns out, we do want to use careful write. We just 01340 don't want to block, but we do want to at least *try* 01341 to write out all the samples. 01342 */ 01343 careful_write(fd, f->data, f->datalen, 0); 01344 } 01345 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) { 01346 char tmp[2]; 01347 01348 tmp[0] = f->subclass; 01349 tmp[1] = '\0'; 01350 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) { 01351 ret = 0; 01352 ast_frfree(f); 01353 break; 01354 } else if (option_debug > 1) 01355 ast_log(LOG_DEBUG, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp, exitcontext); 01356 } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) { 01357 ret = 0; 01358 ast_frfree(f); 01359 break; 01360 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) { 01361 if (ioctl(fd, ZT_SETCONF, &ztc_empty)) { 01362 ast_log(LOG_WARNING, "Error setting conference\n"); 01363 close(fd); 01364 ast_frfree(f); 01365 goto outrun; 01366 } 01367 01368 /* if we are entering the menu, and the user has a channel-driver 01369 volume adjustment, clear it 01370 */ 01371 if (!menu_active && user->talk.desired && !user->talk.actual) 01372 set_talk_volume(user, 0); 01373 01374 if (musiconhold) { 01375 ast_moh_stop(chan); 01376 } 01377 if ((confflags & CONFFLAG_ADMIN)) { 01378 /* Admin menu */ 01379 if (!menu_active) { 01380 menu_active = 1; 01381 /* Record this sound! */ 01382 if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) { 01383 dtmf = ast_waitstream(chan, AST_DIGIT_ANY); 01384 ast_stopstream(chan); 01385 } else 01386 dtmf = 0; 01387 } else 01388 dtmf = f->subclass; 01389 if (dtmf) { 01390 switch(dtmf) { 01391 case '1': /* Un/Mute */ 01392 menu_active = 0; 01393 if (ztc.confmode & ZT_CONF_TALKER) { 01394 ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; 01395 confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; 01396 } else { 01397 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; 01398 confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; 01399 } 01400 if (ioctl(fd, ZT_SETCONF, &ztc)) { 01401 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); 01402 ret = -1; 01403 break; 01404 } 01405 if (ztc.confmode & ZT_CONF_TALKER) { 01406 if (!ast_streamfile(chan, "conf-unmuted", chan->language)) 01407 ast_waitstream(chan, ""); 01408 } else { 01409 if (!ast_streamfile(chan, "conf-muted", chan->language)) 01410 ast_waitstream(chan, ""); 01411 } 01412 break; 01413 case '2': /* Un/Lock the Conference */ 01414 menu_active = 0; 01415 if (conf->locked) { 01416 conf->locked = 0; 01417 if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) 01418 ast_waitstream(chan, ""); 01419 } else { 01420 conf->locked = 1; 01421 if (!ast_streamfile(chan, "conf-lockednow", chan->language)) 01422 ast_waitstream(chan, ""); 01423 } 01424 break; 01425 case '3': /* Eject last user */ 01426 menu_active = 0; 01427 usr = conf->lastuser; 01428 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) { 01429 if(!ast_streamfile(chan, "conf-errormenu", chan->language)) 01430 ast_waitstream(chan, ""); 01431 } else 01432 usr->adminflags |= ADMINFLAG_KICKME; 01433 ast_stopstream(chan); 01434 break; 01435 case '4': 01436 tweak_listen_volume(user, VOL_DOWN); 01437 break; 01438 case '6': 01439 tweak_listen_volume(user, VOL_UP); 01440 break; 01441 case '7': 01442 tweak_talk_volume(user, VOL_DOWN); 01443 break; 01444 case '8': 01445 menu_active = 0; 01446 break; 01447 case '9': 01448 tweak_talk_volume(user, VOL_UP); 01449 break; 01450 default: 01451 menu_active = 0; 01452 /* Play an error message! */ 01453 if (!ast_streamfile(chan, "conf-errormenu", chan->language)) 01454 ast_waitstream(chan, ""); 01455 break; 01456 } 01457 } 01458 } else { 01459 /* User menu */ 01460 if (!menu_active) { 01461 menu_active = 1; 01462 if (!ast_streamfile(chan, "conf-usermenu", chan->language)) { 01463 dtmf = ast_waitstream(chan, AST_DIGIT_ANY); 01464 ast_stopstream(chan); 01465 } else 01466 dtmf = 0; 01467 } else 01468 dtmf = f->subclass; 01469 if (dtmf) { 01470 switch(dtmf) { 01471 case '1': /* Un/Mute */ 01472 menu_active = 0; 01473 if (ztc.confmode & ZT_CONF_TALKER) { 01474 ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; 01475 confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; 01476 } else if (!(user->adminflags & ADMINFLAG_MUTED)) { 01477 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; 01478 confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; 01479 } 01480 if (ioctl(fd, ZT_SETCONF, &ztc)) { 01481 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); 01482 ret = -1; 01483 break; 01484 } 01485 if (ztc.confmode & ZT_CONF_TALKER) { 01486 if (!ast_streamfile(chan, "conf-unmuted", chan->language)) 01487 ast_waitstream(chan, ""); 01488 } else { 01489 if (!ast_streamfile(chan, "conf-muted", chan->language)) 01490 ast_waitstream(chan, ""); 01491 } 01492 break; 01493 case '4': 01494 tweak_listen_volume(user, VOL_DOWN); 01495 break; 01496 case '6': 01497 tweak_listen_volume(user, VOL_UP); 01498 break; 01499 case '7': 01500 tweak_talk_volume(user, VOL_DOWN); 01501 break; 01502 case '8': 01503 menu_active = 0; 01504 break; 01505 case '9': 01506 tweak_talk_volume(user, VOL_UP); 01507 break; 01508 default: 01509 menu_active = 0; 01510 if (!ast_streamfile(chan, "conf-errormenu", chan->language)) 01511 ast_waitstream(chan, ""); 01512 break; 01513 } 01514 } 01515 } 01516 if (musiconhold) 01517 ast_moh_start(chan, NULL); 01518 01519 if (ioctl(fd, ZT_SETCONF, &ztc)) { 01520 ast_log(LOG_WARNING, "Error setting conference\n"); 01521 close(fd); 01522 ast_frfree(f); 01523 goto outrun; 01524 } 01525 01526 conf_flush(fd, chan); 01527 } else if (option_debug) { 01528 ast_log(LOG_DEBUG, 01529 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n", 01530 chan->name, f->frametype, f->subclass); 01531 } 01532 ast_frfree(f); 01533 } else if (outfd > -1) { 01534 res = read(outfd, buf, CONF_SIZE); 01535 if (res > 0) { 01536 memset(&fr, 0, sizeof(fr)); 01537 fr.frametype = AST_FRAME_VOICE; 01538 fr.subclass = AST_FORMAT_SLINEAR; 01539 fr.datalen = res; 01540 fr.samples = res/2; 01541 fr.data = buf; 01542 fr.offset = AST_FRIENDLY_OFFSET; 01543 if (user->listen.actual) 01544 ast_frame_adjust_volume(&fr, user->listen.actual); 01545 if (ast_write(chan, &fr) < 0) { 01546 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno)); 01547 } 01548 } else 01549 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); 01550 } 01551 lastmarked = currentmarked; 01552 } 01553 } 01554 01555 if (musiconhold) 01556 ast_moh_stop(chan); 01557 01558 if (using_pseudo) 01559 close(fd); 01560 else { 01561 /* Take out of conference */ 01562 ztc.chan = 0; 01563 ztc.confno = 0; 01564 ztc.confmode = 0; 01565 if (ioctl(fd, ZT_SETCONF, &ztc)) { 01566 ast_log(LOG_WARNING, "Error setting conference\n"); 01567 } 01568 } 01569 01570 reset_volumes(user); 01571 01572 ast_mutex_lock(&conflock); 01573 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) 01574 conf_play(chan, conf, LEAVE); 01575 01576 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER)) { 01577 if (ast_fileexists(user->namerecloc, NULL, NULL)) { 01578 if ((conf->chan) && (conf->users > 1)) { 01579 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language)) 01580 ast_waitstream(conf->chan, ""); 01581 if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language)) 01582 ast_waitstream(conf->chan, ""); 01583 } 01584 ast_filedelete(user->namerecloc, NULL); 01585 } 01586 } 01587 ast_mutex_unlock(&conflock); 01588 01589 outrun: 01590 ast_mutex_lock(&conflock); 01591 01592 if (confflags & CONFFLAG_MONITORTALKER && dsp) 01593 ast_dsp_free(dsp); 01594 01595 if (user->user_no) { /* Only cleanup users who really joined! */ 01596 manager_event(EVENT_FLAG_CALL, "MeetmeLeave", 01597 "Channel: %s\r\n" 01598 "Uniqueid: %s\r\n" 01599 "Meetme: %s\r\n" 01600 "Usernum: %d\r\n", 01601 chan->name, chan->uniqueid, conf->confno, user->user_no); 01602 conf->users--; 01603 if (confflags & CONFFLAG_MARKEDUSER) 01604 conf->markedusers--; 01605 if (!conf->users) { 01606 /* No more users -- close this one out */ 01607 conf_free(conf); 01608 } else { 01609 /* Remove the user struct */ 01610 if (user == conf->firstuser) { 01611 if (user->nextuser) { 01612 /* There is another entry */ 01613 user->nextuser->prevuser = NULL; 01614 } else { 01615 /* We are the only entry */ 01616 conf->lastuser = NULL; 01617 } 01618 /* In either case */ 01619 conf->firstuser = user->nextuser; 01620 } else if (user == conf->lastuser){ 01621 if (user->prevuser) 01622 user->prevuser->nextuser = NULL; 01623 else 01624 ast_log(LOG_ERROR, "Bad bad bad! We're the last, not the first, but nobody before us??\n"); 01625 conf->lastuser = user->prevuser; 01626 } else { 01627 if (user->nextuser) 01628 user->nextuser->prevuser = user->prevuser; 01629 else 01630 ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n"); 01631 if (user->prevuser) 01632 user->prevuser->nextuser = user->nextuser; 01633 else 01634 ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n"); 01635 } 01636 } 01637 /* Return the number of seconds the user was in the conf */ 01638 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime)); 01639 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs); 01640 } 01641 free(user); 01642 ast_mutex_unlock(&conflock); 01643 01644 return ret; 01645 }
|
|
Definition at line 508 of file app_meetme.c. References ast_cli(), and RESULT_SUCCESS. 00509 { 00510 ast_cli(fd, "Deprecated! Please use 'meetme' instead.\n"); 00511 00512 return RESULT_SUCCESS; 00513 }
|
|
Definition at line 1742 of file app_meetme.c. References ast_channel::_state, ast_answer(), ast_log(), ast_say_number(), AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_conference::chan, find_conf(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_WARNING, pbx_builtin_setvar_helper(), strsep(), and ast_conference::users. Referenced by load_module(). 01743 { 01744 struct localuser *u; 01745 int res = 0; 01746 struct ast_conference *conf; 01747 int count; 01748 char *confnum, *localdata; 01749 char val[80] = "0"; 01750 01751 if (ast_strlen_zero(data)) { 01752 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n"); 01753 return -1; 01754 } 01755 01756 LOCAL_USER_ADD(u); 01757 01758 localdata = ast_strdupa(data); 01759 if (!localdata) { 01760 ast_log(LOG_ERROR, "Out of memory!\n"); 01761 LOCAL_USER_REMOVE(u); 01762 return -1; 01763 } 01764 01765 confnum = strsep(&localdata,"|"); 01766 conf = find_conf(chan, confnum, 0, 0, NULL, NULL); 01767 if (conf) 01768 count = conf->users; 01769 else 01770 count = 0; 01771 01772 if (!ast_strlen_zero(localdata)){ 01773 /* have var so load it and exit */ 01774 snprintf(val, sizeof(val), "%d",count); 01775 pbx_builtin_setvar_helper(chan, localdata, val); 01776 } else { 01777 if (chan->_state != AST_STATE_UP) 01778 ast_answer(chan); 01779 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */ 01780 } 01781 LOCAL_USER_REMOVE(u); 01782 01783 return res; 01784 }
|
|
Provides a description of the module.
Definition at line 2286 of file app_meetme.c. 02287 { 02288 return (char *) tdesc; 02289 }
|
|
Definition at line 1647 of file app_meetme.c. References ast_mutex_lock(), cfg, ast_conference::confno, confs, ast_conference::next, and var. Referenced by count_exec(). 01649 { 01650 struct ast_config *cfg; 01651 struct ast_variable *var; 01652 struct ast_conference *cnf; 01653 01654 /* Check first in the conference list */ 01655 ast_mutex_lock(&conflock); 01656 for (cnf = confs; cnf; cnf = cnf->next) { 01657 if (!strcmp(confno, cnf->confno)) 01658 break; 01659 } 01660 ast_mutex_unlock(&conflock); 01661 01662 if (!cnf) { 01663 if (dynamic) { 01664 /* No need to parse meetme.conf */ 01665 ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno); 01666 if (dynamic_pin) { 01667 if (dynamic_pin[0] == 'q') { 01668 /* Query the user to enter a PIN */ 01669 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, AST_MAX_EXTENSION - 1, 0) < 0) 01670 return NULL; 01671 } 01672 cnf = build_conf(confno, dynamic_pin, "", make, dynamic); 01673 } else { 01674 cnf = build_conf(confno, "", "", make, dynamic); 01675 } 01676 } else { 01677 /* Check the config */ 01678 cfg = ast_config_load(CONFIG_FILE_NAME); 01679 if (!cfg) { 01680 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME); 01681 return NULL; 01682 } 01683 var = ast_variable_browse(cfg, "rooms"); 01684 while (var) { 01685 if (!strcasecmp(var->name, "conf")) { 01686 /* Separate the PIN */ 01687 char *pin, *pinadmin, *conf; 01688 01689 if ((pinadmin = ast_strdupa(var->value))) { 01690 conf = strsep(&pinadmin, "|,"); 01691 pin = strsep(&pinadmin, "|,"); 01692 if (!strcasecmp(conf, confno)) { 01693 /* Bingo it's a valid conference */ 01694 if (pin) 01695 if (pinadmin) 01696 cnf = build_conf(confno, pin, pinadmin, make, dynamic); 01697 else 01698 cnf = build_conf(confno, pin, "", make, dynamic); 01699 else 01700 if (pinadmin) 01701 cnf = build_conf(confno, "", pinadmin, make, dynamic); 01702 else 01703 cnf = build_conf(confno, "", "", make, dynamic); 01704 break; 01705 } 01706 } 01707 } 01708 var = var->next; 01709 } 01710 if (!var) { 01711 ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno); 01712 } 01713 ast_config_destroy(cfg); 01714 } 01715 } else if (dynamic_pin) { 01716 /* Correct for the user selecting 'D' instead of 'd' to have 01717 someone join into a conference that has already been created 01718 with a pin. */ 01719 if (dynamic_pin[0] == 'q') 01720 dynamic_pin[0] = '\0'; 01721 } 01722 01723 if (cnf) { 01724 if (confflags && !cnf->chan && 01725 !ast_test_flag(confflags, CONFFLAG_QUIET) && 01726 ast_test_flag(confflags, CONFFLAG_INTROUSER)) { 01727 ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n"); 01728 ast_clear_flag(confflags, CONFFLAG_INTROUSER); 01729 } 01730 01731 if (confflags && !cnf->chan && 01732 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) { 01733 ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n"); 01734 ast_clear_flag(confflags, CONFFLAG_RECORDCONF); 01735 } 01736 } 01737 01738 return cnf; 01739 }
|
|
Definition at line 2042 of file app_meetme.c. References ast_conference::firstuser, and user. 02043 { 02044 struct ast_conf_user *user = NULL; 02045 int cid; 02046 02047 if (!conf || !callerident) { 02048 return NULL; 02049 } 02050 02051 sscanf(callerident, "%i", &cid); 02052 02053 user = conf->firstuser; 02054 while (user) { 02055 if (user->user_no == cid) 02056 break; 02057 user = user->nextuser; 02058 } 02059 02060 return user; 02061 }
|
|
Definition at line 260 of file app_meetme.c. 00261 { 00262 if (x > 0) 00263 return "(talking)"; 00264 else if (x < 0) 00265 return "(unmonitored)"; 00266 else 00267 return "(not talking)"; 00268 }
|
|
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; }
Definition at line 2300 of file app_meetme.c. References ASTERISK_GPL_KEY. 02301 { 02302 return ASTERISK_GPL_KEY; 02303 }
|
|
Definition at line 2223 of file app_meetme.c. References ast_config_destroy(), ast_config_load(), ast_log(), ast_variable_retrieve(), cfg, CONFIG_FILE_NAME, DEFAULT_AUDIO_BUFFERS, LOG_NOTICE, and LOG_WARNING. 02224 { 02225 struct ast_config *cfg; 02226 char *val; 02227 02228 audio_buffers = DEFAULT_AUDIO_BUFFERS; 02229 02230 if (!(cfg = ast_config_load(CONFIG_FILE_NAME))) 02231 return; 02232 02233 if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) { 02234 if ((sscanf(val, "%d", &audio_buffers) != 1)) { 02235 ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val); 02236 audio_buffers = DEFAULT_AUDIO_BUFFERS; 02237 } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) { 02238 ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n", 02239 ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS); 02240 audio_buffers = DEFAULT_AUDIO_BUFFERS; 02241 } 02242 if (audio_buffers != DEFAULT_AUDIO_BUFFERS) 02243 ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers); 02244 } 02245 02246 ast_config_destroy(cfg); 02247 }
|
|
Initialize the module. Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
Definition at line 2264 of file app_meetme.c. References admin_exec(), ast_cli_register(), ast_register_application(), cli_conf, cli_show_confs, conf_exec(), count_exec(), and load_config(). 02265 { 02266 int res; 02267 02268 load_config(); 02269 02270 res = ast_cli_register(&cli_show_confs); 02271 res |= ast_cli_register(&cli_conf); 02272 res |= ast_register_application(app3, admin_exec, synopsis3, descrip3); 02273 res |= ast_register_application(app2, count_exec, synopsis2, descrip2); 02274 res |= ast_register_application(app, conf_exec, synopsis, descrip); 02275 02276 return res; 02277 }
|
|
Definition at line 2180 of file app_meetme.c. References ast_closestream(), AST_FRAME_VOICE, ast_frfree(), ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_stopstream(), ast_waitfor(), ast_writefile(), ast_writestream(), ast_conference::chan, ast_filestream::f, MEETME_RECORD_ACTIVE, MEETME_RECORD_OFF, MEETME_RECORD_TERMINATE, ast_conference::recording, ast_conference::recordingfilename, ast_conference::recordingformat, and s. Referenced by conf_run(). 02181 { 02182 struct ast_conference *cnf = args; 02183 struct ast_frame *f=NULL; 02184 int flags; 02185 struct ast_filestream *s; 02186 int res=0; 02187 02188 if (!cnf || !cnf->chan) { 02189 pthread_exit(0); 02190 } 02191 ast_stopstream(cnf->chan); 02192 flags = O_CREAT|O_TRUNC|O_WRONLY; 02193 s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644); 02194 02195 if (s) { 02196 cnf->recording = MEETME_RECORD_ACTIVE; 02197 while (ast_waitfor(cnf->chan, -1) > -1) { 02198 f = ast_read(cnf->chan); 02199 if (!f) { 02200 res = -1; 02201 break; 02202 } 02203 if (f->frametype == AST_FRAME_VOICE) { 02204 res = ast_writestream(s, f); 02205 if (res) { 02206 ast_frfree(f); 02207 break; 02208 } 02209 } 02210 ast_frfree(f); 02211 if (cnf->recording == MEETME_RECORD_TERMINATE) { 02212 ast_mutex_lock(&conflock); 02213 ast_mutex_unlock(&conflock); 02214 break; 02215 } 02216 } 02217 cnf->recording = MEETME_RECORD_OFF; 02218 ast_closestream(s); 02219 } 02220 pthread_exit(0); 02221 }
|
|
Reload stuff. This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.
Definition at line 2279 of file app_meetme.c. References load_config(). 02280 { 02281 load_config(); 02282 02283 return 0; 02284 }
|
|
Definition at line 400 of file app_meetme.c. References ast_channel_setoption(), AST_OPTION_RXGAIN, AST_OPTION_TXGAIN, and user. 00401 { 00402 signed char zero_volume = 0; 00403 00404 ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 00405 ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0); 00406 }
|
|
Definition at line 329 of file app_meetme.c. References ast_channel_setoption(), AST_OPTION_TXGAIN, and user. Referenced by tweak_listen_volume(). 00330 { 00331 signed char gain_adjust; 00332 00333 /* attempt to make the adjustment in the channel driver; 00334 if successful, don't adjust in the frame reading routine 00335 */ 00336 gain_adjust = gain_map[volume + 5]; 00337 00338 return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0); 00339 }
|
|
Definition at line 317 of file app_meetme.c. References ast_channel_setoption(), AST_OPTION_RXGAIN, and user. Referenced by conf_run(), and tweak_talk_volume(). 00318 { 00319 signed char gain_adjust; 00320 00321 /* attempt to make the adjustment in the channel driver; 00322 if successful, don't adjust in the frame reading routine 00323 */ 00324 gain_adjust = gain_map[volume + 5]; 00325 00326 return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0); 00327 }
|
|
Definition at line 388 of file app_meetme.c. References set_listen_volume(), tweak_volume(), and user. 00389 { 00390 tweak_volume(&user->listen, action); 00391 /* attempt to make the adjustment in the channel driver; 00392 if successful, don't adjust in the frame reading routine 00393 */ 00394 if (!set_listen_volume(user, user->listen.desired)) 00395 user->listen.actual = 0; 00396 else 00397 user->listen.actual = user->listen.desired; 00398 }
|
|
Definition at line 376 of file app_meetme.c. References set_talk_volume(), tweak_volume(), and user. 00377 { 00378 tweak_volume(&user->talk, action); 00379 /* attempt to make the adjustment in the channel driver; 00380 if successful, don't adjust in the frame reading routine 00381 */ 00382 if (!set_talk_volume(user, user->talk.desired)) 00383 user->talk.actual = 0; 00384 else 00385 user->talk.actual = user->talk.desired; 00386 }
|
|
Definition at line 341 of file app_meetme.c. References volume::desired, VOL_DOWN, and VOL_UP. Referenced by tweak_listen_volume(), and tweak_talk_volume(). 00342 { 00343 switch (action) { 00344 case VOL_UP: 00345 switch (vol->desired) { 00346 case 5: 00347 break; 00348 case 0: 00349 vol->desired = 2; 00350 break; 00351 case -2: 00352 vol->desired = 0; 00353 break; 00354 default: 00355 vol->desired++; 00356 break; 00357 } 00358 break; 00359 case VOL_DOWN: 00360 switch (vol->desired) { 00361 case -5: 00362 break; 00363 case 2: 00364 vol->desired = 0; 00365 break; 00366 case 0: 00367 vol->desired = -2; 00368 break; 00369 default: 00370 vol->desired--; 00371 break; 00372 } 00373 } 00374 }
|
|
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).
Definition at line 2249 of file app_meetme.c. References ast_cli_unregister(), ast_unregister_application(), cli_conf, cli_show_confs, and STANDARD_HANGUP_LOCALUSERS. 02250 { 02251 int res; 02252 02253 res = ast_cli_unregister(&cli_show_confs); 02254 res |= ast_cli_unregister(&cli_conf); 02255 res |= ast_unregister_application(app3); 02256 res |= ast_unregister_application(app2); 02257 res |= ast_unregister_application(app); 02258 02259 STANDARD_HANGUP_LOCALUSERS; 02260 02261 return res; 02262 }
|
|
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.
Definition at line 2291 of file app_meetme.c. References STANDARD_USECOUNT. 02292 { 02293 int res; 02294 02295 STANDARD_USECOUNT(res); 02296 02297 return res; 02298 }
|
|
Definition at line 60 of file app_meetme.c. |
|
Definition at line 61 of file app_meetme.c. |
|
Definition at line 62 of file app_meetme.c. |
|
Definition at line 175 of file app_meetme.c. |
|
Initial value: { {"meetme", NULL, NULL }, conf_cmd, "Execute a command on a conference or conferee", conf_usage, complete_confcmd} Definition at line 723 of file app_meetme.c. Referenced by load_module(), and unload_module(). |
|
Initial value: { { "show", "conferences", NULL }, confs_show, "Show status of conferences", show_confs_usage, NULL } Definition at line 518 of file app_meetme.c. Referenced by load_module(), and unload_module(). |
|
Initial value: "Usage: meetme (un)lock|(un)mute|kick|list <confno> <usernumber>\n" " Executes a command for the conference or on a conferee\n" Definition at line 719 of file app_meetme.c. |
|
Referenced by admin_exec(), build_conf(), conf_exec(), conf_free(), and find_conf(). |
|
Definition at line 68 of file app_meetme.c. |
|
Definition at line 106 of file app_meetme.c. |
|
Definition at line 113 of file app_meetme.c. |
|
Definition at line 303 of file app_meetme.c. |
|
Definition at line 130 of file app_meetme.c. |
|
|
|
Initial value:
"Deprecated! Please use 'meetme' instead.\n"
Definition at line 515 of file app_meetme.c. |
|
Definition at line 128 of file app_meetme.c. |
|
Definition at line 64 of file app_meetme.c. |
|
Definition at line 65 of file app_meetme.c. |
|
Definition at line 66 of file app_meetme.c. |
|
Definition at line 58 of file app_meetme.c. |