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